home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / mus / play / DES_Tracker2_00.lha / DTL / code / LScope.S < prev    next >
Text File  |  1993-12-17  |  100KB  |  3,196 lines

  1. ;;=======================================================================;;
  2. ;;               L-Scope.S  -  Begun Tue, Mar 10, 1992.                  ;;
  3. ;;                     Last updated Dec 18, 1993                          ;;
  4. ;;-----------------------------------------------------------------------;;
  5. ;;           This is version 2.0 of the visual scope program             ;;
  6. ;;           for destracker.library rel 2.0+  (lib ver 3.0+)             ;;
  7. ;;-----------------------------------------------------------------------;;
  8. ;;              Designed and written by Darren E. Schebek                ;;
  9. ;;              Copyright ©1992,1993 by Darren E. Schebek                ;;
  10. ;;                         All rights reserved.                          ;;
  11. ;;                                                                       ;;
  12. ;;                This source code is NOT public domain.                 ;;
  13. ;;                                                                       ;;
  14. ;;=======================================================================;;
  15. ;;                                                                       ;;
  16. ;;      You can contact me at the following address by snail mail:       ;;
  17. ;;                                                                       ;;
  18. ;;                         Darren Schebek                                ;;
  19. ;;                         5620 Sherwood Blvd.                           ;;
  20. ;;                         Delta, BC                                     ;;
  21. ;;                         CANADA                                        ;;
  22. ;;                         V4L-2C5                                       ;;
  23. ;;                                                                       ;;
  24. ;;              Or via usenet:  dschebek@outb.wimsey.bc.ca               ;;
  25. ;;                                                                       ;;
  26. ;;=======================================================================;;
  27.  
  28. ; Include files I need (V37 includes are required)...
  29.  
  30.         Include    "dp:system.gs"    ;DevPac-specific (almost global) include.
  31.  
  32.         INCLUDE    "exec/memory.i"
  33.         INCLUDE    "exec/interrupts.i"
  34.         INCLUDE    "exec/execbase.i"
  35.         INCLUDE    "graphics/gfxbase.i"
  36.         INCLUDE    "hardware/intbits.i"
  37.         INCLUDE    "hardware/custom.i"
  38.  
  39.         INCLUDE    "DTLib.I"
  40.  
  41.  
  42. ; Public variables required by cback.o ...
  43.  
  44.         XDEF    _main        ;These six PUBLIC's are needed
  45.         XDEF    _procname    ;only because I'm linking with
  46.         XDEF    _stack        ;cback.o.  Otherwise, they'd
  47.         XDEF    _priority    ;be chucked before you could say
  48.         XDEF    _BackGroundIO    ;"Use The Force, Luke!"
  49.         XDEF    DOSBase
  50.         XDEF    MemCleanup
  51.  
  52.         XREF    LScopePic
  53.  
  54. ; Some structure definition support macros of my own...
  55.  
  56. LOADLIB    MACRO
  57.     MOVE.L    _\1Base,A6
  58.     ENDM
  59.  
  60. SYS    MACRO
  61.     JSR    _LVO\1(A6)
  62.     ENDM
  63.  
  64. BYTETAB    MACRO            ;Used for rerving space for a table of n bytes.
  65. \1    EQU    SOFFSET
  66. SOFFSET    SET    SOFFSET+\2
  67.     ENDM
  68.  
  69. WORDTAB    MACRO            ;Used for rerving space for a table of n words.
  70. \1    EQU    SOFFSET
  71. SOFFSET    SET    SOFFSET+(\2*2)
  72.     ENDM
  73.  
  74. APTRTAB    MACRO            ;Used for rerving space for a table of n pointers.
  75. \1    EQU    SOFFSET
  76. SOFFSET    SET    SOFFSET+(\2*4)
  77.     ENDM
  78.  
  79. LONGTAB    MACRO            ;Used for rerving space for a table of n longwords.
  80. \1    EQU    SOFFSET
  81. SOFFSET    SET    SOFFSET+(\2*4)
  82.     ENDM
  83.  
  84. _SYSBase    = 4        ;_SysBase holds pointer to... well... SysBase.
  85.  
  86. NDOTS        = 32    ;Number of pixels per scope. Also the scope's height.
  87.  
  88. ; The ChannelScope structure...
  89.  
  90.     STRUCTURE CHANNELSCOPE,0
  91.     APTR    csc_ScreenBaseAddr    ;Ptr to left center of channel's scope.
  92.     APTR    csc_CurSamplePtr    ;Ptr to current sample data position.
  93.     APTR    csc_SampleEnd        ;Ptr to end of sample data.
  94.     APTR    csc_RepeatEnd        ;Ptr to end of repeat part of sample.
  95.     ULONG    csc_SampleStep        ;Current step for sample index (based on period).
  96.     ULONG    csc_RepeatDist        ;Distance from end of sample to start of repeat part.
  97.     ULONG    csc_ConsecRepDist    ;Dist. from end of repeat part to start of repeat part.
  98.     UWORD    csc_Frac        ;Fractional portion of current sample index.
  99.     UWORD    csc_Period        ;Current period being played in channel.
  100.     UBYTE    csc_Volume        ;Current volume level of channel.
  101.     UBYTE    csc_Pad            ;Reserved byte, always 0.
  102.     APTR    csc_AmplitudeTable    ;Ptr to scanline offsets for scaling amplitudes.
  103.     WORDTAB    csc_OldPositions,NDOTS    ;Table of old pixel positions from previous frame.
  104.     BYTETAB    csc_Amplitudes,NDOTS    ;Table of amplitudes from current frame for averaging.
  105.     LABEL    csc_SIZEOF
  106.  
  107. ; The variables required by the program...
  108.  
  109.     STRUCTURE LSCOPE,0
  110.     APTR    IntuiBase    ;Pointer to IntuitionBase.
  111.     APTR    GFXBase        ;Pointer to GfxBase.
  112.     APTR    DosBase        ;Pointer to DosBase.
  113.     APTR    DTLBase        ;Pointer to DTLBase.
  114.     APTR    LScopeTaskPtr    ;Pointer to LScope's TCB.
  115.     APTR    MyWindow    ;Pointer to my window structure.
  116.     APTR    MyMessage    ;Pointer to my message structure.
  117.     APTR    MyMessagePort    ;Pointer to my message port structure.
  118.     APTR    VBIntAddr    ;Pointer to my (VBlank) interrupt structure.
  119.     APTR    PackedPicPtr    ;Peter Piper picked a peck of packed pics. :)
  120.     APTR    FileAddr    ;More temp. storage for LoadDisplay.
  121.     ULONG    FileSize    ;And still more.
  122.  
  123. ; VBlank variables ("old" below means one vblank old, which is really getting
  124. ; on in computer terms :).
  125.  
  126.     APTR    Plane0Addr    ;Will hold pointer to plane 0 of display.
  127.     APTR    Plane1Addr    ;Will hold ptr to plane 1.
  128.     APTR    DrawPlaneAddr    ;Address of third plane that gets drawn to.
  129.     UWORD    RestoreP0    ;Used to buffer background for peak meter code.
  130.     UWORD    RestoreP1    ;Also used to buffer background.
  131.     APTRTAB    OldInsts,4    ;Holds old insts used by each channel.
  132.     UBYTE    LeftLevel    ;Holds left output level display.
  133.     UBYTE    RightLevel    ;Holds right output level display.
  134.     BYTETAB    OldLeftVol,2    ;Two bytes for old channel 0 & 3 peak volumes.
  135.     BYTETAB    OldRightVol,2    ;Two bytes for old channel 1 & 2 peak volumes.
  136.     BYTETAB    ChBarHeights,4    ;Height of each channel's volume bar.
  137.     BYTETAB    ChOldVolumes,4    ;Holds channel volumes one VBlank old.
  138.     UBYTE    NewNoteHits    ;Bits 0 to 3 hold new note hits (Bit=1 means hit).
  139.     UBYTE    DrawNAFlag    ;Clear & no module loaded means clear value stats.
  140.  
  141. ; The following variables are essentially copies of their DTLBase counterparts.
  142. ; They are compared with the correspnding DTL_Base values and if the two values
  143. ; don't match, the VBlank routine will update the display element for that
  144. ; value.  This keeps the VBlank from having to redraw the entire display on
  145. ; every single vertical blank.  Instead, the VBlank routine redraws only the
  146. ; display elements that have changed since the last VBlank...
  147.  
  148.     UBYTE    OldFlags    ;Old contents of high byte of dtl_Flags.
  149.     UBYTE    OldLFlags    ;Old contents of low byte of dtl_Flags.
  150.     UBYTE    OldGlobalVolume    ;Old contents of dtl_GlobalVolume.
  151.     UBYTE    OldCurPosition    ;Old contents of dtl_CurPosition.
  152.     BYTE    OldGlobalTempo    ;Old contents of dtl_GlobalTempo (signed byte).
  153.     UBYTE    OldCurrentTempo    ;Old contents of dtl_CurrentTempo.
  154.     UBYTE    OldStartPos    ;Old contents of dtl_StartPosition.
  155.     UBYTE    OldEndPos    ;Old contents of dtl_EndPosition.
  156.     UBYTE    OldCurNote    ;Old contents of dtl_CurNoteIndex.
  157.     UBYTE    OldStartNote    ;Old contents of dtl_StartNoteIndex.
  158.     UBYTE    OldEndNote    ;Old contents of dtl_EndNoteIndex.
  159.     UBYTE    OldNumIters    ;Old contents of dtl_Iterations.
  160.     UBYTE    OldItersToGo    ;Old contents of dtl_IterationsToGo.
  161.     UBYTE    OldStatus    ;Old contents of low byte of dtl_Flags (again).
  162.     UBYTE    OldJiffies    ;Old number of elapsed jiffies.
  163.     UBYTE    OldFineTempo    ;Old contents of dtl_FineTempo.
  164.     ULONG    OldCurHertz    ;Old contents of dtl_CurrentHz.
  165.  
  166.     UBYTE    VBSigBit    ;Used by VBlank to signal main() when VBlank freq. changes.
  167.     UBYTE    RedrawSigBit    ;Used by VBlank to signal main code to redraw display.
  168.     UBYTE    CurVBFreq    ;Current VBlank frequency in Hz.
  169.     UBYTE    AlreadyBlankFlag ;Set when all channel scopes are "turned off".
  170.     UBYTE    LeftOutput
  171.     UBYTE    RightOutput
  172.     UBYTE    LastCh0Output
  173.     UBYTE    LastCh1Output
  174.     UBYTE    LastCh2Output
  175.     UBYTE    LastCh3Output
  176.  
  177.     APTR    BaseTablePtr      ;Ptr to table of base frequencies based on USA/Euro platform.
  178.     APTR    LeftScreenAddrP0  ;Ptr to left-center pixel position for left output scope, plane 0.
  179.     APTR    RightScreenAddrP0 ;Ptr to left-center pixel position for right output scope, plane 0.
  180.     APTR    LeftScreenAddrP1  ;Ptr to left-center pixel position for left output scope, plane 2.
  181.     APTR    RightScreenAddrP1 ;Ptr to left-center pixel position for right output scope, plane 2.
  182.  
  183.     STRUCT    Channel0,csc_SIZEOF ;CHANNELSCOPE structure for audio channel #0.
  184.     STRUCT    Channel1,csc_SIZEOF ;CHANNELSCOPE structure for audio channel #1.
  185.     STRUCT    Channel2,csc_SIZEOF ;CHANNELSCOPE structure for audio channel #2.
  186.     STRUCT    Channel3,csc_SIZEOF ;CHANNELSCOPE structure for audio channel #3.
  187.  
  188.     APTRTAB    ScaleTablePtrs,65    ;Table of ptrs to amplitude scaling tables.
  189.     WORDTAB    OldLeftAmplitudes,NDOTS    ;Holds pixel positions for previous frame (left output scope).
  190.     WORDTAB    OldRightAmplitudes,NDOTS ;Holds pixel positions for previous frame (right output scope).
  191.     LONGTAB    DotStepsTable,800    ;Table of sample steps, indexed with period.
  192.     WORDTAB    PeriodsTable,800    ;Table of ((period*NDOTS)/2). Used to build DotStepsTable.
  193.     BYTETAB    TablesBuffer,(NDOTS*65) ;Holds all tables pointed to by ScaleTablePtrs.
  194.  
  195.     LABEL    LS_SIZE        ;Size of the L-Scope variable storage area.
  196.  
  197. ; These are the flags used for my window...
  198.  
  199. MYIDCMP        = MOUSEBUTTONS        ;"I want mouse button events".
  200. MYWFLAGS    = BORDERLESS|BACKDROP    ;Tell how to draw window.
  201.  
  202. ; These are constants used in dealing with my low resolution bitmap display...
  203.  
  204. BPWIDTH        = 320
  205. BPHEIGHT    = 200
  206. BPBYTESPERROW    = (BPWIDTH/8)
  207.  
  208. ; These are screen bitmap offsets to various positions on the screen where
  209. ; things are drawn...
  210.  
  211. ENABLEOFFSET    = (136*BPBYTESPERROW)+2      ;Leftmost channel enable "light".
  212. MNAMEOFFSET    = (200*BPBYTESPERROW)+7   ;1st char of module name.
  213. LEFTOFFSET    = (123*BPBYTESPERROW)+18  ;Leftmost "light" of left peak meter.
  214. RIGHTOFFSET    = (133*BPBYTESPERROW)+18  ;Leftmost "light" of right peak meter.
  215. INAMEOFFSET    = (63*BPBYTESPERROW)+17      ;1st char of channel #0 instrument name.
  216. INAMEDISTANCE    = (14*BPBYTESPERROW)      ;Distance to next inst text field.
  217. GVOLOFFSET    = (147*BPBYTESPERROW)+10  ;1st char of global volume display.
  218. GTEMPOOFFSET    = (157*BPBYTESPERROW)+9   ;1st char of global tempo display.
  219. FINETEMPOOFFSET    = (165*BPBYTESPERROW)+9   ;1st char of global fine tempo display.
  220. CURTEMPOOFFSET    = (175*BPBYTESPERROW)+10  ;1st char of current tempo display.
  221. HERTZOFFSET    = (185*BPBYTESPERROW)+7   ;1st char of current hertz display.
  222. CURPOSOFFSET    = (147*BPBYTESPERROW)+23  ;1st char of current position display.
  223. SPOSOFFSET    = (158*BPBYTESPERROW)+23  ;1st char of start position display.
  224. EPOSOFFSET    = (166*BPBYTESPERROW)+23  ;1st char of end position display.
  225. NITEROFFSET    = (177*BPBYTESPERROW)+23  ;1st char of num of iterations display.
  226. LITEROFFSET    = (185*BPBYTESPERROW)+23  ;1st char of iterations left display.
  227. CNOTEOFFSET    = (147*BPBYTESPERROW)+36  ;1st char of current note display.
  228. SNOTEOFFSET    = (158*BPBYTESPERROW)+36  ;1st char of start note display.
  229. ENOTEOFFSET    = (166*BPBYTESPERROW)+36  ;1st char of end note display.
  230. STATUSOFFSET    = (185*BPBYTESPERROW)+27  ;1st char of status text display.
  231. TIMEROFFSET    = (200*BPBYTESPERROW)+28  ;1st char of elapsed time display.
  232.  
  233. COBASE        = (61*(BPWIDTH/8))+2        ;Makes for less table-typing :).
  234. BOTTOMCVROW    = (63*BPBYTESPERROW)+COBASE ;Bottom of first channel volume bar.
  235.  
  236. ; These are constants that define the pixel location on my screen of the
  237. ; upper left corner of the EXIT button (a bit kludgey, but hey, it's only an
  238. ; example program)...
  239.  
  240. EXITULX        = 3
  241. EXITULY        = 3
  242. EXITLRX        = 11
  243. EXITLRY        = 11
  244.  
  245. _main
  246. Start        
  247.  
  248. ; First, allocate space for program variables...
  249.  
  250.         Move.L    _SYSBase,A6
  251.         Move.L    #LS_SIZE,D0
  252.         Move.L    #MEMF_CLEAR,D1
  253.         SYS    AllocMem
  254.         Tst.L    D0        ;Allocate error?
  255.         Ble    ProgAbort    ;Yup, leave immediately.
  256.         Move.L    D0,A4        ;Nobody's allowed to touch A4!
  257.  
  258.         St    VBSigBit(A4)
  259.         St    RedrawSigBit(A4)
  260.  
  261. ; Open intuition.library...
  262.  
  263.         Lea    IntName(PC),A1        ;Library name pointer in A1.
  264.         MoveQ    #0,D0
  265.         SYS    OpenLibrary        ;Attempt to open library.
  266.         Move.L    D0,IntuiBase(A4)    ;Save pointer to library base.
  267.         Beq    .Error            ;Pointer = 0 means trouble!
  268.  
  269. ; Open graphics.library...
  270.  
  271.         Lea    GfxName(PC),A1
  272.         MoveQ    #0,D0
  273.         SYS    OpenLibrary
  274.         Move.L    D0,GFXBase(A4)
  275.         Beq    .Error
  276.  
  277. ; Open destracker.library v3.0+ (which opens dos.library for me)...
  278.  
  279.         Lea    DTLName(PC),A1
  280.         MoveQ    #3,D0
  281.         SYS    OpenLibrary
  282.         Move.L    D0,DTLBase(A4)
  283.         Beq    .Error
  284.  
  285. ; Save pointer to DosBase...
  286.  
  287.         Move.L    D0,A0              ;Put DTLBase pointer in addr reg.
  288.         Move.L    dtl_DosLib(A0),DosBase(A4) ;Copy DosBase pointer.
  289.  
  290. ; Allocate a signal bit to use...
  291.  
  292.         MoveQ    #-1,D0
  293.         SYS    AllocSignal
  294.         Move.B    D0,VBSigBit(A4)
  295.         Bmi    .Error
  296.  
  297. ; Allocate another signal bit to use...
  298.  
  299.         MoveQ    #-1,D0
  300.         SYS    AllocSignal
  301.         Move.B    D0,RedrawSigBit(A4)
  302.         Bmi    .Error
  303.  
  304. ;------------------------------
  305. ; Initialization code follows.  I should tell you now that just about every
  306. ; scrap of code in this program that deals with determining the current
  307. ; VBlank frequency is completely and utterly wrong.  I've tried to determine
  308. ; how to do this correctly for all versions of the O.S. quickly, but to no
  309. ; avail.  Not having any kind of developer status certainly doesn't help,
  310. ; either.  Very, very frustrating.  Anyways, the VBlankFrequency field in
  311. ; Execbase, contrary to what might seem obvious, does NOT hold the current
  312. ; VBlank frequency.  I believe it always holds 60 on a North American Amiga,
  313. ; and always 50 on a European Amiga.  Go figure out the thinking behind that
  314. ; one...
  315.  
  316. ; Bump up my task priority...
  317.  
  318.         LOADLIB    SYS
  319.         Sub.L    A1,A1
  320.         SYS    FindTask
  321.         Move.L    D0,LScopeTaskPtr(A4)
  322.  
  323.         Move.L    D0,A1
  324.         MoveQ    #50,D0
  325.         SYS    SetTaskPri
  326.  
  327. ; Determine current VBlank frequency...
  328.  
  329.         Bsr    CalcVBlankFrequency
  330.         Move.B    D0,CurVBFreq(A4)
  331.  
  332. ; Determine platform type (N.American or European) and select the
  333. ; appropriate base constants table...
  334.  
  335.         Lea    BaseNAmerica,A0
  336.         Move.L    GFXBase(A4),A1
  337.         Move.W    gb_DisplayFlags(A1),D0
  338.         BTst    #PAL,D0
  339.         Beq    .StoreBase
  340.  
  341.         Lea    BaseEurope,A0
  342.  
  343. .StoreBase    Move.L    A0,BaseTablePtr(A4)
  344.  
  345. ; Build the Lookup tables for scaling amplitudes based on channel volume...
  346.  
  347.         Bsr    BuildLUTables
  348.  
  349.         Bsr    BuildDotStepsTable
  350.  
  351. ; Initialize each of the channel structures...
  352.  
  353.         Lea    Channel0(A4),A0
  354.         Bsr    InitChannel
  355.         Lea    Channel1(A4),A0
  356.         Bsr    InitChannel
  357.         Lea    Channel2(A4),A0
  358.         Bsr    InitChannel
  359.         Lea    Channel3(A4),A0
  360.         Bsr    InitChannel
  361.  
  362. ; I have to prime certain variables that are used by the VBlank.  Since my
  363. ; VBlank routine will only update the display for these variables if they
  364. ; differ from their DTLBase counterparts, I store -1 in them so that when
  365. ; L-Scope is first run, the VBlank routine will automagically update the
  366. ; display for these variables...
  367.  
  368.         MoveQ    #0,D0
  369.         Move.B    D0,LeftOutput(A4)
  370.         Move.B    D0,RightOutput(A4)
  371.         Move.B    D0,LeftLevel(A4)
  372.         Move.B    D0,RightLevel(A4)
  373.  
  374.         MoveQ    #-1,D0
  375.         Move.B    D0,OldStartPos(A4)
  376.         Move.B    D0,OldEndPos(A4)
  377.         Move.B    D0,OldStartNote(A4)
  378.         Move.B    D0,OldEndNote(A4)
  379.         Move.B    D0,OldCurNote(A4)
  380.         Move.B    D0,OldGlobalVolume(A4)
  381.         Move.B    D0,OldCurPosition(A4)
  382.         Move.B    D0,OldGlobalTempo(A4)
  383.         Move.B    D0,OldNumIters(A4)
  384.         Move.B    D0,OldItersToGo(A4)
  385.         Move.B    D0,OldCurrentTempo(A4)
  386.         Move.B    D0,OldStatus(A4)
  387.         Move.B    D0,OldJiffies(A4)
  388.         Move.B    D0,OldFineTempo(A4)
  389.         Move.L    D0,OldCurHertz(A4)
  390.  
  391. ; Now, since the DTLBase note-hit flags could be anything when L-Scope is first
  392. ; run (even if no song is playing), I copy them directly to my OldFlags variable
  393. ; to make sure that L-Scope doesn't think that any note-hits just occurred...
  394.  
  395.         Move.L    DTLBase(A4),A6            ;Get ptr to DTL_Base.
  396.         Move.B    dtl_Flags(A6),OldFlags(A4)    ;Update note hit flags.
  397.  
  398. ; Now open my own screen. My newscreen structure tells OpenScreen to initially
  399. ; place my screen at the bottom of the display.  I do this so that I can set up
  400. ; the screen's display and palette while the screen is out of view, then use
  401. ; MoveScreen to pop it up to the top of the display.  This way I avoid unpleasant
  402. ; wipes and flicker while creating my display and setting the palette...
  403.  
  404.         Move.L    IntuitionBase(A4),A6
  405.         Lea    MyNewScreen(PC),A0 ;Ptr to my newscreen structure in A0.
  406.         SYS    OpenScreen
  407.         Move.L    D0,NWScreen    ;Store screen ptr in my newwindow struct.
  408.         Beq    .Error        ;Couldn't open screen.
  409.  
  410. ; Now open my window, which fills the entire screen except for the screen's
  411. ; title bar (So you can still drag the screen up and down)...
  412.  
  413.         Lea    MyNewWindow(PC),A0 ;Ptr to my newwindow structure in A0.
  414.         SYS    OpenWindow
  415.         Move.L    D0,MyWindow(A4)    ;Save pointer to my window structure.
  416.         Beq    .Error        ;oops, something went wrong, so abort.
  417.  
  418. ; Now set up my message port.  I use the newly created window's UserPort...
  419.  
  420.         Move.L    D0,A0        ;Window pointer in A0.
  421.         Move.L    wd_UserPort(A0),MyMessagePort(A4)
  422.  
  423.  
  424. ; Now, to reduce the amount of indirect addressing I'll need to do later on
  425. ; (and speed up the vblank code a bit), I extract the pointers to the bitplanes
  426. ; into which I do all rendering from my screen's bitmap structure.  The
  427. ; screen is made up of three bitplanes.  Bitplanes 0 and 1 contain the actual
  428. ; picture, and bitplane 2 is mostly blank (and is the bitplane into which most
  429. ; rendering is done, independently of the other two planes)...
  430.  
  431.         Move.L    NWScreen,A0    ;Fetch pointer to my screen structure.
  432.         Lea    sc_BitMap(A0),A1
  433.         Move.L    bm_Planes(A1),Plane0Addr(A4)
  434.         Move.L    bm_Planes+4(A1),Plane1Addr(A4)
  435.         Move.L    bm_Planes+8(A1),DrawPlaneAddr(A4)
  436.  
  437. ; Set the screen base addresses for each of the six oscilloscopes...
  438.  
  439.         Move.L    bm_Planes+8(A1),D0
  440.         Add.L    #(BPBYTESPERROW*30)+9,D0
  441.  
  442.         Move.L    D0,Channel0+csc_ScreenBaseAddr(A4)
  443.         AddQ.L    #5,D0
  444.         Move.L    D0,Channel3+csc_ScreenBaseAddr(A4)
  445.         AddQ.L    #8,D0
  446.         Move.L    D0,Channel1+csc_ScreenBaseAddr(A4)
  447.         AddQ.L    #5,D0
  448.         Move.L    D0,Channel2+csc_ScreenBaseAddr(A4)
  449.  
  450. ; The left and right output scopes are rendered on two planes to get their
  451. ; yellow color, so I have two screen base address variables for each of them...
  452.  
  453.         Move.L    bm_Planes(A1),D0
  454.         Add.L    #(BPBYTESPERROW*30)+3,D0
  455.         Move.L    D0,LeftScreenAddrP0(A4)
  456.         Add.L    #30,D0
  457.         Move.L    D0,RightScreenAddrP0(A4)
  458.  
  459.         Move.L    bm_Planes+8(A1),D0
  460.         Add.L    #(BPBYTESPERROW*30)+3,D0
  461.         Move.L    D0,LeftScreenAddrP1(A4)
  462.         Add.L    #30,D0
  463.         Move.L    D0,RightScreenAddrP1(A4)
  464.  
  465. ; Call UnpackDisplay to unpack the L-Scope display data to my screen's
  466. ; bitmap memory...
  467.  
  468.         Move.L    NWScreen,A0    ;Fetch pointer to my screen structure.
  469.         Bsr    UnpackDisplay
  470.  
  471. ; Save a small portion of the display that will likely be trashed...
  472.  
  473.         Move.L    Plane0Addr(A4),A1
  474.         Move.W    LEFTOFFSET(A1),RestoreP0(A4)
  475.         Move.L    Plane1Addr(A4),A1
  476.         Move.W    LEFTOFFSET(A1),RestoreP1(A4)
  477.  
  478. ; Now I install my vertical blank routine.  This is one of the last things I do
  479. ; because a lot of variables have to be initialized first. Once I install the
  480. ; VBlank routine, it starts going right away, and the variables it uses had
  481. ; better bloody well be initialized by then =u) ...
  482.  
  483.         Bsr    InstallVBlank
  484.         Tst    D0
  485.         Bmi    .Error        ;Couldn't install VBlank routine. Abort.
  486.  
  487. ; Now that my screen is all drawn and set up, I can "pop" it to the top of the
  488. ; display using MoveScreen...
  489.  
  490.         Move.L    IntuitionBase(A4),A6    ;MoveScreen is Intuition function.
  491.         Move.L    NWScreen,A0        ;Pointer to my screen in A0.
  492.         SYS    ScreenToFront
  493.  
  494. ; Now prep the main loop by caching some important pointers...
  495.  
  496.         Move.L    _SYSBase,A6        ;SYSBase pointer in A6.
  497.         Move.L    MyMessagePort(A4),A5    ;Cache message port addr in A5.
  498.  
  499. ;===============================
  500.  
  501. ; Now the main loop begins.  In it, I basically wait for an input event (I will
  502. ; only receive mouse button events).  If I get anything other than a SELECTUP
  503. ; event, I just reply to the message and loop back to wait for another event.
  504. ; If, however, I do get a SELECTUP event, I check the mouse X and Y coordinates
  505. ; reported in the message to see if the mouse was over the EXIT button on my
  506. ; display. If not, I reply to the message and loop back for another event. If
  507. ; so, I fall out of the main loop and exit.
  508. ;
  509. ; I also wait on two other signal bits.  Both are used by the VBlank interrupt
  510. ; to signal the main code.  One is used whenever the VBlank interrupt detects
  511. ; that the frequency of the VBlank interrupt has changed (the oscilloscope code
  512. ; needs to know the current VBlank frequency so it knows how many samples to
  513. ; display per VBlank frame).  The other is used whenever the VBLank interrupt
  514. ; occurs, and it tells the main code to redraw the display.
  515.  
  516.         MoveQ    #0,D7
  517.         Move.B    MP_SIGBIT(A5),D1    ;Wait for window message.
  518.         BSet    D1,D7
  519.         Move.B    VBSigBit(A4),D1        ;Wait also for signal from VBlank.
  520.         BSet    D1,D7
  521.         Move.B    RedrawSigBit(A4),D1    ;Wait for redraw signal as well.
  522.         BSet    D1,D7
  523.  
  524. .MainLoop    Move.L    D7,D0            ;Specify signal bits to wait for.
  525.         SYS    Wait            ;*ZZZzzzz...*
  526.  
  527.         Move.B    RedrawSigBit(A4),D1
  528.         BTst    D1,D0            ;Redraw the display?
  529.         Beq    .NoRedraw        ;Nope.
  530.  
  531.         Bsr    RedrawDisplay        ;Yup, redraw the display.
  532.  
  533. .NoRedraw    Move.B    VBSigBit(A4),D1        ;*znork!* huh? wazzat?
  534.         BTst    D1,D0            ;Oh, did VBlank signal me?
  535.         Beq    .NoVBChange        ;Nope.
  536.  
  537.         Bsr    BuildDotStepsTable    ;Yup, VBlank frequency changed.
  538.  
  539. .NoVBChange    Move.L    A5,A0        ;Get message port address.
  540.         SYS    GetMsg        ;Fetcheth the message.
  541.         Tst.L    D0        ;Did I get anything?
  542.         Beq.S    .MainLoop    ;Nope.
  543.  
  544.         Move.L    D0,A1        ;Yup, get pointer into an address reg.
  545.  
  546.         Move.W    im_Code(A1),D2    ;Fetch relevant info.
  547.         Move.W    im_MouseX(A1),D3
  548.         Move.W    im_MouseY(A1),D4
  549.  
  550.         Move.L    D0,A1        ;Message pointer to A1.
  551.         SYS    ReplyMsg    ;Reply right away.
  552.  
  553.         Cmp.W    #SELECTUP,D2    ;Left mouse button released?
  554.         Bne.S    .MainLoop    ;Nope. Wait for another message.
  555.  
  556.         Cmp.W    #EXITULX,D3    ;Mouse to left of exit button?
  557.         Blt.S    .MainLoop    ;Yup, missed.
  558.         Cmp.W    #EXITULY,D4    ;Mouse above exit button?
  559.         Blt.S    .MainLoop    ;Yup.
  560.         Cmp.W    #EXITLRX,D3    ;Mouse to the right of exit button?
  561.         Bgt.S    .MainLoop    ;Yup. No go.
  562.         Cmp.W    #EXITLRY,D4    ;Mouse below exit button?
  563.         Bgt.S    .MainLoop    ;Yup. Missed.
  564.  
  565. ;------------------------------
  566. ; User clicked on the exit button, so deallocate everything and leave...
  567.  
  568. ; Relieve the vertical blank routine from active duty...
  569.  
  570. .Exit        Bsr    RemoveVBlank
  571.  
  572. ; Free up the VBlank signal bit...
  573.  
  574. .Error        LOADLIB    SYS
  575.         MoveQ    #0,D0
  576.         Move.B    VBSigBit(A4),D0
  577.         Bmi    .RDSigBit
  578.  
  579.         SYS    FreeSignal
  580.  
  581. .RDSigBit    MoveQ    #0,D0
  582.         Move.B    RedrawSigBit(A4),D0
  583.         Bmi    .NoSigBit
  584.  
  585.         SYS    FreeSignal
  586.  
  587. ; Close my window...
  588.  
  589. .NoSigBit    Move.L    IntuiBase(A4),A6
  590.         Move.L    MyWindow(A4),D0
  591.         Beq    .1
  592.         Move.L    D0,A0
  593.         SYS    CloseWindow
  594.  
  595. ; Close my screen...
  596.  
  597. .1        Move.L    IntuiBase(A4),A6
  598.         Move.L    NWScreen,D0
  599.         Beq    .2
  600.         Move.L    D0,A0
  601.         SYS    CloseScreen
  602.  
  603. ; Close the destracker.library...
  604.  
  605. .2        Move.L    _SYSBase,A6
  606.         Move.L    DTLBase(A4),D0
  607.         Beq    .3
  608.         Move.L    D0,A1
  609.         SYS    CloseLibrary
  610.  
  611. ; Close the graphics.library...
  612.  
  613. .3        Move.L    GFXBase(A4),D0
  614.         Beq    .4
  615.         Move.L    D0,A1
  616.         SYS    CloseLibrary
  617.  
  618. ; Close the intuition.library...
  619.  
  620. .4        Move.L    IntuiBase(A4),D0
  621.         Beq    .5
  622.         Move.L    D0,A1
  623.         SYS    CloseLibrary
  624.  
  625. ; Free up the memory used by my variables...
  626.  
  627. .5        Move.L    A4,A1
  628.         Move.L    #LS_SIZE,D0
  629.         SYS    FreeMem
  630.  
  631. ; Dat's it!  We be gone...
  632.  
  633. MemCleanup    MoveQ    #0,D0        ;Success return code in D0.
  634. Leave        Rts            ;Exit program.
  635.  
  636. ProgAbort    MoveQ    #10,D0        ;Error return code in D0.
  637.         Bra.S    Leave        ;Exit program.
  638.  
  639.  
  640. ;;=======================;;
  641. ;; Subroutines follow... ;;
  642. ;;=======================;;
  643.  
  644. ;---------------------------------------------------------------
  645. ; CalcVBlankFrequency routine.  This function determines the frequency
  646. ; of the vertical blank for all versions of the operating system.  Note
  647. ; that hardware hacks (like PAL-booters) are not supported.  If you have
  648. ; a North American Amiga (NTSC) and you want to run with a PAL display, then
  649. ; upgrade to WB 2.0 or higher.  Really.  At this stage in the game, if you
  650. ; are still running WB 1.3 or lower, it's definitely time to upgrade.
  651. ;
  652. ;  Input: Nothing.
  653. ;
  654. ; Output: D0.B = Current VBlank frequency in Hertz (?..255).
  655. ;
  656.  
  657. CalcVBlankFrequency
  658.  
  659.         Move.L    A6,-(Sp)
  660.  
  661.         LOADLIB    SYS
  662.         Cmp.B    #36,LIB_VERSION(A6)
  663.         Bls.S    .AD13
  664.  
  665. ; Proper VBlank frequency calc for AmigaDOS v2.0 and up...
  666.  
  667. .AD20AndUp    Move.L    GFXBase(A4),A6
  668.         Move.L    #(2000000000/280),D0
  669.         Move.W    gb_current_tot_rows(A6),D1
  670.         MulU    gb_current_tot_cclks(A6),D1
  671.         DivU    D1,D0
  672.         AddQ.W    #1,D0
  673.         Lsr.W    #1,D0
  674.         Bra.S    .Done
  675.  
  676. ; Proper VBlank frequency calc for AmigaDOS v1.3 or lower...
  677.  
  678. .AD13        Move.B    VBlankFrequency(A6),D0  ;Perhaps CBM made the same assumption. :)
  679.  
  680.  
  681. .Done        Move.L    (Sp)+,A6
  682.         Rts
  683.  
  684. ;---------------------------------------------------------------
  685. ; InitChannel routine.  Initializes the specified CHANNELSCOPE structure.
  686. ;
  687. ;  Input: A0 = Pointer to the channel structure.
  688. ;
  689. ; Output: Nothing.
  690. ;
  691.  
  692. InitChannel    Move.L    A2,-(Sp)
  693.  
  694.         Move.L    A0,A2
  695.         Lea    BlankSample,A0
  696.         Lea    4(A0),A1
  697.         Move.L    ScaleTablePtrs(A4),D1
  698.         MoveQ    #0,D0
  699.  
  700.         Move.L    A0,csc_CurSamplePtr(A2)
  701.         Move.L    A1,csc_SampleEnd(A2)
  702.         Move.L    A1,csc_RepeatEnd(A2)
  703.         Move.L    #4,csc_RepeatDist(A2)
  704.         Move.L    #4,csc_ConsecRepDist(A2)
  705.         Move.L    D0,csc_SampleStep(A2)        
  706.         Move.W    D0,csc_Period(A2)
  707.         Move.L    D1,csc_AmplitudeTable(A2)
  708.         Move.B    D0,csc_Volume(A2)
  709.  
  710.         Move.L    (Sp)+,A2
  711.         Rts
  712.  
  713. ;---------------------------------------------------------------
  714. ; BuildDotStepsTable routine.  This will recalculate the DotStepsTable
  715. ; based on VBlank frequency and platform (i.e. North American or European).
  716. ; It is called from the main code only: once during intialization, and
  717. ; then whenever the VBlank frequency changes (VBlank signals main code
  718. ; whenever this occurs)...
  719.  
  720. BuildDotStepsTable
  721.         Move.L    D2,-(Sp)
  722.  
  723.         Move.L    BaseTablePtr(A4),A0
  724.         MoveQ    #0,D0
  725.         Move.B    CurVBFreq(A4),D0
  726.         Sub.W    #30,D0
  727.         Bpl    .1
  728.  
  729.         MoveQ    #30,D0
  730.  
  731. .1        Cmp.W    #50,D0
  732.         Ble    .2
  733.  
  734.         MoveQ    #50,D0
  735.  
  736. .2        Add.W    D0,D0
  737.         Add.W    D0,D0
  738.         Move.L    0(A0,D0.W),D1
  739.  
  740.         Lea    PeriodsTable(A4),A0
  741.         Lea    DotStepsTable(A4),A1
  742.         Move.W    #800-1,D0
  743.  
  744. .Loop        Move.L    D1,D2
  745.         DivU    (A0)+,D2
  746.         Swap    D2
  747.         Clr.W    D2
  748.         Swap    D2
  749.         Lsl.L    #8,D2
  750.         Move.L    D2,(A1)+
  751.  
  752.         DBra    D0,.Loop
  753.  
  754.         Move.L    (Sp)+,D2
  755.         Rts        
  756.  
  757. ;---------------------------------------------------------------
  758. ; BuildLUTables.  This function builds the lookup tables required for
  759. ; the auto-scaling of amplitudes based on playback channel volume.
  760. ;
  761.  
  762. BuildLUTables    MoveM.L    D2-D4/A2/A3,-(Sp)
  763.  
  764.         Lea    ScaleTablePtrs(A4),A1
  765.         Lea    TablesBuffer(A4),A0
  766.         Lea    ScanlineSteps,A2
  767.         Lea    ScanlineStarts,A3
  768.         MoveQ    #65-1,D0    ;Build a table for each volume value.
  769.  
  770. .TableLoop    Move.L    A0,D2
  771.         Add.L    #16,D2
  772.         Move.L    D2,(A1)+
  773.         MoveQ    #0,D1
  774.         Move.B    (A3)+,D1
  775.         Ext.W    D1
  776.         Swap    D1
  777.         Move.L    (A2)+,D2
  778.         MoveQ    #NDOTS-1,D3    ;Each table is NDOTS (scope height) elements.
  779.  
  780. .ElementLoop    Move.L    D1,D4
  781.         Add.L    #$8000,D4
  782.         Swap    D4
  783.         Move.B    D4,(A0)+
  784.         Add.L    D2,D1
  785.  
  786.         DBra    D3,.ElementLoop
  787.  
  788.         DBra    D0,.TableLoop
  789.  
  790. ; Now build the periods table...
  791.  
  792.         Lea    PeriodsTable(A4),A0
  793.         MoveQ    #108,D1
  794.         Move.W    #800-1,D0
  795.  
  796. .PerLoop    Move.W    D1,D2
  797.         MulU    #NDOTS,D2
  798.         Lsr.L    #1,D2
  799.         Move.W    D2,(A0)+
  800.  
  801.         AddQ    #1,D1
  802.         DBra    D0,.PerLoop
  803.  
  804.         MoveM.L    (Sp)+,D2-D4/A2/A3
  805.         Rts
  806.  
  807. ;---------------------------------------------------------------
  808. ; UnpackIFFRow routine. Unpacks a single line of a single plane of a packed
  809. ; IFF ILBM.  This routine was written by Colin Fox and he let me use it.
  810. ; Unfortunately, he didn't comment it.  I optimized it a bit, and I commented
  811. ; that bit. :)
  812. ;
  813. ; Input:  A0 =     Ptr to variable holding address of BODY chunk (past ID & length).
  814. ;      A1 =    Ptr to destination bitplane line.
  815. ;      D0 =    Pixel width of destination line.
  816. ;
  817. ; Output: D0 = # of bytes written to destination.
  818. ;
  819.  
  820. UnpackIFFRow    MoveM.L    D2/D6/A2-A4,-(Sp)
  821.  
  822.         Move.L    A0,A2
  823.         Move.L    A1,A3
  824.         Move.W    D0,D6
  825.         AddQ.W    #7,D6
  826.         Lsr.W    #3,D6
  827.         Move.L    (A2),A4
  828.         MoveQ    #0,D2
  829.  
  830. .Check        Cmp.W    D2,D6
  831.         Ble.S    .Exit
  832.  
  833.         Move.B    (A4)+,D0
  834.         Ext.W    D0
  835.         Bmi.S    .CheckRepeat
  836.  
  837.         Add.W    D0,D2
  838.         AddQ    #1,D2
  839.  
  840. .StartCopy    Move.B    (A4)+,(A3)+
  841.         DBra    D0,.StartCopy
  842.         Bra.S    .Check
  843.  
  844. .CheckRepeat    Neg.W    D0    ;D0 is negative here. Negate it again.
  845.         Bmi.S    .Check    ;If still negative, then D0 = 128.
  846.  
  847.         Add.W    D0,D2
  848.         AddQ    #1,D2
  849.         Move.B    (A4)+,D1
  850.  
  851. .StartReplicate    Move.B    D1,(A3)+
  852.         DBra    D0,.StartReplicate
  853.         Bra.S    .Check
  854.  
  855. .Exit        Move.L    A4,(A2)
  856.         Move.L    D6,D0
  857.  
  858.         MoveM.L    (Sp)+,D2/D6/A2-A4
  859.         Rts
  860.  
  861. ;---------------------------------------------------------------
  862. ; UnpackDisplay routine.  Unpacks the L-Scope display picture to the (at this
  863. ; point) newly created SCREEN's bitmap planes.
  864. ;
  865. ;     Input:    A0 = Pointer to the SCREEN structure.
  866. ;        A4 = Pointer to L-Scope variables.
  867. ;
  868. ;    Output: None.
  869. ;
  870. UnpackDisplay    MoveM.L    D2-D3/A0-A3/A5-A6,-(Sp)
  871.  
  872.         Move.L    A0,A3        ;Put screen pointer in a safe place.
  873.  
  874. ; Set the palette for the screen...
  875.  
  876.         Lea    sc_ViewPort(A3),A0    ;Ptr to screen's viewport in A0.
  877.         Lea    PicPalette,A1        ;Ptr to my palette in A1.
  878.         MoveQ    #8,D0            ;8 colors to load.
  879.         Move.L    GFXBase(A4),A6
  880.         SYS    LoadRGB4
  881.  
  882. ; Now unpack the picture's planes to the screen's bitmap planes...
  883.  
  884.         Move.L    A3,A5
  885.         Lea    LScopePic,A0
  886.         Move.L    A0,PackedPicPtr(A4)
  887.         Lea    PackedPicPtr(A4),A0
  888.         Lea    sc_BitMap(A5),A1
  889.         Move.L    bm_Planes+0(A1),A2
  890.         Move.L    bm_Planes+4(A1),A3
  891.         Move.L    bm_Planes+8(A1),A5
  892.         Lea    BPBYTESPERROW*10(A2),A2    ;Skip past screen title (10 lines).
  893.         Lea    BPBYTESPERROW*10(A3),A3    ;(Not terribly kosher, I know).
  894.         Lea    BPBYTESPERROW*10(A5),A5
  895.         Move.W    #200-1,D2        ;Loop to unpack 200 lines.
  896. .UnpackLine    Move.L    A2,A1            ;A1 = Ptr to bitplane #0.
  897.         Move.W    #BPWIDTH,D0        ;Unpack 320 pixels into plane.
  898.         Bsr    UnpackIFFRow        ;Do it.
  899.         Add.W    D0,A1            ;Move to next line in plane.
  900.         Move.L    A1,A2            ;Return updated ptr to A2.
  901.         Move.L    A3,A1            ;Do same for plane #1.
  902.         Move.W    #BPWIDTH,D0
  903.         Bsr    UnpackIFFRow
  904.         Add.W    D0,A1
  905.         Move.L    A1,A3
  906.         Move.L    A5,A1            ;Do same for plane #2.
  907.         Move.W    #BPWIDTH,D0
  908.         Bsr    UnpackIFFRow
  909.         Add.W    D0,A1
  910.         Move.L    A1,A5
  911.         DBra    D2,.UnpackLine        ;Unpack rest of picture data.
  912.  
  913. .Leave        MoveM.L    (Sp)+,D2-D3/A0-A3/A5-A6
  914.         Rts
  915.  
  916. ;---------------------------------------------------------------
  917. ; InstallVBlank routine. Installs my own vertical blank routine using
  918. ; the Exec AddIntServer routine.
  919. ;
  920. ; Input: A4 = Pointer to L-Scope variables.
  921. ;
  922. InstallVBlank    Move.L    _SYSBase,A6
  923.  
  924. ; First, allocate an interrupt structure...
  925.  
  926.         Move.L    #IS_SIZE,D0        ;Size of the interrupt structure.
  927.         Move.L    #MEMF_CLEAR|MEMF_PUBLIC,D1
  928.         SYS    AllocMem
  929.         Move.L    D0,VBIntAddr(A4)    ;Save pointer to int struct.
  930.         Beq    .AllocErr        ;Hmmm. Error. Damn.
  931.  
  932. ; Initialize various fields of the interrupt structure before adding it to
  933. ; the system's interrupt list...
  934.  
  935.         Move.L    D0,A1                ;Need int struct ptr in A1.
  936.         Move.B    #NT_INTERRUPT,LN_TYPE(A1)    ;"I am an interrupt".
  937.         Move.L    #VBlankName,LN_NAME(A1)        ;"My name is..."
  938.         Move.B    #0,LN_PRI(A1)            ;"I'm an average guy".
  939.         Move.L    A4,IS_DATA(A1)    ;VBlank needs ptr to L-Scope variables.
  940.         Lea    LScopeVBlank,A0
  941.         Move.L    A0,IS_CODE(A1)    ;Ptr to vblank routine.
  942.  
  943. ; Add my vblank interrupt to the system's vertical blank interrupt list...
  944.  
  945.         Move.L    #INTB_VERTB,D0
  946.         SYS    AddIntServer
  947.  
  948.         MoveQ    #0,D0        ;Return success condition.
  949. .Leave        Rts
  950.  
  951. .AllocErr    MoveQ    #-1,D0        ;Return error condition.
  952.         Bra.S    .Leave
  953.  
  954. ;---------------------------------------------------------------
  955. ; RemoveVBlank routine. Relieves my vertical blank routine from active duty.
  956. ;
  957. ; Input: A4 = Pointer to L-Scope variables.
  958. ;
  959. RemoveVBlank    Move.L    _SYSBase,A6
  960.  
  961. ; First make sure that my vblank is currenty installed...
  962.  
  963.         Tst.L    VBIntAddr(A4)
  964.         Beq    .Done
  965.  
  966. ; Call Exec's RemInServer routine to rip my vblank routine right outa there...
  967.  
  968.         Move.L    VBIntAddr(A4),A1
  969.         Move.L    #INTB_VERTB,D0
  970.         SYS    RemIntServer
  971.  
  972. ; Deallocate the memory used by my interrupt structure...
  973.  
  974.         Move.L    #IS_SIZE,D0
  975.         Move.L    VBIntAddr(A4),A1
  976.         SYS    FreeMem
  977.  
  978. .Done        Rts
  979.  
  980. ;------------------------------
  981. ; This macro is used for updating the current sample, playback period,
  982. ; volume, etc. for a specific CHANNELSCOPE structure.
  983.  
  984. UPDATECHANNEL    MACRO
  985.  
  986.         Lea    Channel\1(A4),A0
  987.         Lea    dtl_Channel\1(A6),A1
  988.  
  989.         BTst    #\1,dtl_Flags+1(A6)    ;Is channel enabled?
  990.         Bne.S    .Enabled\1        ;Yup, proceed.
  991.  
  992.         Lea    BlankSample,A3        ;Nope, no output for this channel.
  993.         Move.L    A3,csc_CurSamplePtr(A0)
  994.         Lea    4(A3),A3
  995.         Move.L    A3,csc_SampleEnd(A0)
  996.         Clr.L    csc_SampleStep(A0)
  997.         Clr.W    csc_Frac(A0)
  998.         Bra    .Done\1
  999.  
  1000. .Enabled\1    BTst    #\1,NewNoteHits(A4)    ;New note hit in Channel?
  1001.         Beq.S    .CheckPeriod\1        ;Nope.
  1002.  
  1003. ; Set up new sample data...
  1004.  
  1005.         Move.L    cs_Instrument(A1),A3
  1006.         Move.L    is_Address(A3),D1
  1007.         Move.L    D1,csc_CurSamplePtr(A0)
  1008.         Move.L    D1,D2
  1009.         Add.L    is_Length(A3),D1
  1010.         Move.L    D1,csc_SampleEnd(A0)
  1011.         Add.L    is_Repeat(A3),D2
  1012.         Add.L    is_RepeatLen(A3),D2
  1013.         Move.L    D2,csc_RepeatEnd(A0)
  1014.         Move.L    is_Length(A3),D1
  1015.         Sub.L    is_Repeat(A3),D1
  1016.         Move.L    D1,csc_RepeatDist(A0)
  1017.         MoveQ    #0,D0
  1018.         Move.W    D0,csc_Frac(A0)
  1019.         Move.L    is_RepeatLen(A3),D1
  1020.         Cmp.L    #9,D1
  1021.         Bgt.S    .HasRep\1
  1022.         MoveQ    #0,D1
  1023. .HasRep\1    Move.L    D1,csc_ConsecRepDist(A0)
  1024.  
  1025. ; Check to see if a sample offset has been used...
  1026.  
  1027.         Move.L    cs_SampleOffset(A1),D0
  1028.         Beq.S    .CheckPeriod\1
  1029.  
  1030.         Add.L    D0,csc_CurSamplePtr(A0)
  1031.  
  1032. ; Check to see if the period has changed...
  1033.  
  1034. .CheckPeriod\1    Move.W    cs_Period(A1),D0
  1035.         Cmp.W    csc_Period(A0),D0
  1036.         Beq.S    .CheckVolume\1
  1037.  
  1038.         Move.W    D0,csc_Period(A0)
  1039.         Sub.W    #108,D0
  1040.         Bpl.S    .HavePer\1
  1041.  
  1042.         MoveQ    #0,D0
  1043.  
  1044. .HavePer\1    Add.W    D0,D0
  1045.         Add.W    D0,D0
  1046.         Move.L    0(A2,D0.W),csc_SampleStep(A0)
  1047.  
  1048. ; Check to see if the channel volume has changed...
  1049.  
  1050. .CheckVolume\1    MoveQ    #0,D0
  1051.         Move.B    cs_RealVolume(A1),D0
  1052.         Cmp.B    csc_Volume(A0),D0
  1053.         Beq.S    .Done\1
  1054.  
  1055.         Move.B    D0,csc_Volume(A0)
  1056.         Add.W    D0,D0
  1057.         Add.W    D0,D0
  1058.         Move.L    0(A5,D0.W),csc_AmplitudeTable(A0)
  1059.  
  1060. .Done\1
  1061.         ENDM
  1062.  
  1063. ;------------------------------
  1064. ; This macro handles the rendering of a single pixel for one of the
  1065. ; four audio channels' oscilloscope display.  It looks frighteningly
  1066. ; CPU-intensive, considering it only draws one pixel, but it really does
  1067. ; a lot more than that.  It takes a raw sample element, scales it based on
  1068. ; the current channel's volume, then converts that into a scanline offset.
  1069. ; It also records the scanline position of the pixel for later averaging
  1070. ; to produce the left/right total output data.
  1071. ;
  1072. ; Register setup for this macro invocation:
  1073. ;
  1074. ; D0 = Holds fractional sample index in low word.
  1075. ; D1 = Holds fractional portion of dot-step in low word.
  1076. ; D2 = Holds pointer to end of instrument sample (or end of repeat loop).
  1077. ; D3 = Scratch.  Used for rendering amplitude pixels.
  1078. ; D4 = Unused.
  1079. ; D5 = Holds integer portion of dot-step in low word.
  1080. ; D6 = Pixel Offset.  Determines which bit gets set in a screen memory byte.
  1081. ; D7 = Scratch.  Used for amplitude scaling and scanline computation.
  1082. ; A0 = Pointer to WScope CHANNEL structure.
  1083. ; A1 = Pointer to current instrument sample used by channel.
  1084. ; A2 = Pointer to pixel screen offsets from previous frame for channel.
  1085. ; A3 = Pointer to scanline offset lookup table.
  1086. ; A4 = Pointer to channel's table for storing amplitudes for this frame.
  1087. ; A5 = Pointer to base screen destination for rendering amplitudes.
  1088. ; A6 = Pointer to amplitudes table to store for subsequent averaging.
  1089. ;
  1090.  
  1091.  
  1092.  
  1093. DRAWCHDOT    MACRO
  1094.  
  1095.         Add.W    D1,D0
  1096.         Bcc.S    .NoWrapYet\1
  1097.         AddQ.W    #1,A1
  1098. .NoWrapYet\1    Add.W    D5,A1
  1099.         Cmp.L    D2,A1
  1100.         Blo.S    .NotEnd\1
  1101.  
  1102. ; End of sample reached, loop back...
  1103.  
  1104.         Sub.L    csc_RepeatDist(A0),A1
  1105.         Move.L    csc_RepeatEnd(A0),D2
  1106.         Move.L    csc_ConsecRepDist(A0),csc_RepeatDist(A0)
  1107.         Bne.S    .NotEnd\1
  1108.  
  1109. ; Control gets here if instrument is one-shot (i.e. no repeat loop)...
  1110.  
  1111.         Lea    BlankSample,A1
  1112.         Move.L    A1,D2
  1113.         AddQ.L    #4,D2
  1114.         MoveQ    #0,D1
  1115.  
  1116. ; Get amplitude from sample., scale it according to volume, and convert it
  1117. ; into a scanline offset for rendering the dot...
  1118.  
  1119. .NotEnd\1    MoveQ    #0,D7
  1120.         Move.B    (A1),D7
  1121.         Ext.W    D7
  1122.         Asr.W    #3,D7        ;D7 now -16..+15
  1123.         Move.B    0(A6,D7.W),D7    ;Get scanline #(-16..15) corrected for channel volume.
  1124.         Move.B    D7,(A4)+    ;Save for left/right meters.
  1125.         Ext.W    D7        ;Extend sign.
  1126.         Add.W    D7,D7        ;Make a word index out of it.
  1127.         Move.W    0(A3,D7.W),D7    ;Get scanline offset.
  1128.  
  1129. ; Erase this amplitude's dot at its old position
  1130. ; and draw it at the new position...
  1131.  
  1132.         Move.W    (A2),D3
  1133.         BClr    D6,0(A5,D3.W)
  1134.         BSet    D6,0(A5,D7.W)
  1135.         Move.W    D7,(A2)+
  1136.  
  1137. ; Next dot...
  1138.         DBra    D6,.NoWrap\1
  1139.         AddQ.W    #1,A5
  1140.         MoveQ    #8-1,D6
  1141.  
  1142. .NoWrap\1
  1143.         ENDM
  1144.  
  1145. ;------------------------------
  1146. ; This macro is used by the code that creates the left/right total output
  1147. ; oscilloscopes.  It is invoked once for each pixel in each scope.  Each time
  1148. ; it is invoked, it takes output data from two audio channel scopes, averages
  1149. ; them together and then renders a single pixel of the scope (left or right).
  1150. ;
  1151. ; Register setup for this macro invocation:
  1152. ;
  1153. ; D0 = $FFFE        This is used as a mask for averaging calcs.
  1154. ; D1 = Scratch        Work register for averaging calcs.
  1155. ; D2 = Scratch        Work register for pixel rendering.
  1156. ; D3 = Pixel Offset    Determines which bit gets set in a screen memory byte.
  1157. ; D4 = Unused
  1158. ; D5 = Unused
  1159. ; D6 = Unused
  1160. ; D7 = Unused
  1161. ; A0 = Pointer to 1st WScope CHANNEL structure's amplitudes table.
  1162. ; A1 = Pointer to 2nd WScope CHANNEL structure's amplitudes table.
  1163. ; A2 = Pointer to pixel screen offsets from previous frame for left/right channel.
  1164. ; A3 = Pointer to base screen destination for rendering amplitudes.
  1165. ; A4 = Pointer to WScope Global variables.
  1166. ; A5 = Pointer to scanline offset lookup table.
  1167. ; A6 = Pointer to base screen destination for second draw plane (to get yellow).
  1168.  
  1169. DRAWLRDOT    MACRO
  1170.  
  1171.         Move.B    (A0)+,D1
  1172.         Add.B    (A1)+,D1
  1173.         Ext.W    D1
  1174.         And.W    D0,D1
  1175.  
  1176.         Move.W    0(A5,D1.W),D1
  1177.  
  1178. ; Erase this amplitude's dot at its old position and draw it at the new
  1179. ; position.  A little more involved than with the audio channel scopes
  1180. ; because I have to erase/render for two planes instead of one...
  1181.  
  1182.         Move.W    (A2),D2
  1183.         BClr    D3,0(A3,D2.W)
  1184.         BClr    D3,0(A6,D2.W)
  1185.         BSet    D3,0(A3,D1.W)
  1186.         BSet    D3,0(A6,D1.W)
  1187.         Move.W    D1,(A2)+
  1188. ; Next dot...
  1189.  
  1190.         DBra    D3,.Done\1
  1191.         AddQ.W    #1,A3
  1192.         AddQ.W    #1,A6
  1193.         AddQ.W    #8,D3
  1194.  
  1195. .Done\1
  1196.         ENDM
  1197.  
  1198. ;------------------------------
  1199. ; RedrawDisplay routine. This routine is the guts of this whole program.  It
  1200. ; updates the display as fast as it can, and, in some cases, favors speed over
  1201. ; memory (i.e., lots of table lookup, especially for decimal string conversion
  1202. ; and text rendering).  if you're a beginner or intermediate programmer, I hope
  1203. ; you learn a thing or two from this code, since it uses a few programming
  1204. ; optimization tricks, and 68000 tricks as well (but then again, it's far from
  1205. ; being ideal code).  Of course, like all programs, it does contain some code
  1206. ; that you look at and frown.  I'm very displeased with the way the peak meter
  1207. ; rendering logic wound up.  Ah well, maybe one day I'll clean it up...
  1208.  
  1209. RedrawDisplay    MoveM.L    D0-D7/A2-A6,-(Sp)
  1210.  
  1211.         Move.L    DTLBase(A4),A5        ;A5 points to ST library base.
  1212.         Move.L    DrawPlaneAddr(A4),A6    ;Cache draw plane pointer in A6.
  1213.  
  1214.         MoveQ    #0,D7            ;D7 always 0 (my impression of an 88100 :)
  1215.         
  1216. ; Compute the new note-hits that occurred since last vblank and record them
  1217. ; as set bits in NewNoteHits, with bits 0..3 corresponding to sound channels
  1218. ; 0..3 ...
  1219.  
  1220.         Move.B    dtl_Flags(A5),D1    ;Get hi-byte of flags only.
  1221.         And.B    #$0F,D1            ;Only interested in note-hits.
  1222.         Cmp.B    OldFlags(A4),D1        ;Any new ones?
  1223.         Bne    .NewNotes        ;Yup.
  1224.         Move.B    D7,NewNoteHits(A4)    ;No new notes.
  1225.         Bra    .NoNewNotes
  1226.  
  1227. .NewNotes    Move.B    OldFlags(A4),D2        ;Compute new note bits.
  1228.         Move.B    D1,OldFlags(A4)        ;Update OldFlags for next vblank.
  1229.         Eor.B    D2,D1            ;Isolate new note-hits in D1.
  1230.         Move.B    D1,NewNoteHits(A4)    ;Store them for use later on.
  1231. .NoNewNotes
  1232.  
  1233. ; Draw channel enable status "lights".  These are the four "lights" at the
  1234. ; middle of the left side of the screen.  These "lights" are positioned on an
  1235. ; EVEN byte boundary, so they can be rendered using word moves...
  1236.  
  1237.         MoveQ    #4-1,D0            ;Set up to loop for each channel.
  1238.         Move.B    dtl_Flags+1(A5),D1    ;Get channel enable flags in D1.
  1239.         Lea    ENABLEOFFSET(A6),A0    ;Get ptr to channel 0 "light" pos.
  1240. .DCE        MoveQ    #0,D2            ;Assume the channel is disabled.
  1241.         Lsr.W    #1,D1            ;Shift out channel enable status bit.
  1242.         Bcc    .DCE1            ;It was 0, so channel is disabled.
  1243.         Move.W    #$7FFC,D2        ;It was 1, so we draw the "light".
  1244. .DCE1        Move.W    D2,BPBYTESPERROW(A0)    ;Draw 2nd line of "light".
  1245.         Move.W    D2,(A0)+        ;Draw 1st line, move to next "light".
  1246.         DBra    D0,.DCE            ;Loop for rest of sound channels.
  1247.  
  1248. ; Update the channel volume bars.  These are the four bars at the left side of
  1249. ; the middle of the screen.  Each bar is slightly less than one word (16 pixels)
  1250. ; wide, and each is aligned on an even byte boundary, allowing me to use word
  1251. ; moves to draw/erase them.  Also, each bar is exactly 64 pixels in height.
  1252. ; Here, I check each bar and decrement it's height by one if the bar's height
  1253. ; is non-zero (just like the logic that decrements the pitch bars)...
  1254.  
  1255.         MoveQ    #4-1,D0            ;D0 = loop count and channel #.
  1256.         Lea    ChBarHeights+4(A4),A1    ;Get pointer to channel bar heights.
  1257.         Lea    ChannelOffsets(PC),A2    ;Get ptr to channel plane offsets.
  1258.         MoveQ    #0,D2            ;Make sure D2 is clear.
  1259.  
  1260. .UpdateChBars    Move.B    -(A1),D2        ;Get height of this channel bar.
  1261.         Add.W    D2,D2            ;Make word index out of bar height.
  1262.         Move.W    0(A2,D2.W),A3        ;A3 holds offset to top lit line of bar.
  1263.         Add.W    D0,A3            ;Add in (X) offset to correct bar.
  1264.         Add.W    D0,A3            ;Again 'cause they're 2 bytes apart.
  1265.         Add.L    A6,A3            ;A3 now points to topmost lit line of bar.
  1266.         Move.W    D7,(A3)            ;Erase highest lit line of bar.
  1267.         Tst.B    (A1)            ;Is height currently zero?
  1268.         Beq    .NextBar        ;Yup, don't decrement from it any more.
  1269.         SubQ.B    #1,(A1)            ;Nope, reflect new bar height in table.
  1270.  
  1271. .NextBar    DBra    D0,.UpdateChBars    ;Loop for all four channels.
  1272.  
  1273. ; There are certain chores that this vblank routine needs do only while a song is
  1274. ; currently playing.  These chores follow...
  1275.  
  1276.         BTst    #DF_PLAYING,dtl_Flags+1(A5)
  1277.         Bne    .Playing
  1278.  
  1279.         Tst.B    AlreadyBlankFlag(A4)
  1280.         Bne    .NoPlay
  1281.  
  1282. ; This hunk of code only gets called once when the current song stops
  1283. ; playing.  It looks gross, but it's faster than reloading an address
  1284. ; register with the next channel structure's pointer...
  1285.  
  1286.         St    AlreadyBlankFlag(A4)
  1287.  
  1288. ; "Turn off" all channel scopes by setting them to blank samples...
  1289.  
  1290.         Lea    BlankSample,A0
  1291.         Lea    4(A0),A1
  1292.         MoveQ    #0,D0
  1293.         MoveQ    #64,D1
  1294.         Move.L    ScaleTablePtrs+256(A4),D2
  1295.         MoveQ    #4,D3
  1296.         Move.B    D0,NewNoteHits(A4)
  1297.         Move.L    A0,Channel0+csc_CurSamplePtr(A4)
  1298.         Move.L    A0,Channel1+csc_CurSamplePtr(A4)
  1299.         Move.L    A0,Channel2+csc_CurSamplePtr(A4)
  1300.         Move.L    A0,Channel3+csc_CurSamplePtr(A4)
  1301.         Move.L    A1,Channel0+csc_SampleEnd(A4)
  1302.         Move.L    A1,Channel1+csc_SampleEnd(A4)
  1303.         Move.L    A1,Channel2+csc_SampleEnd(A4)
  1304.         Move.L    A1,Channel3+csc_SampleEnd(A4)
  1305.         Move.L    D0,Channel0+csc_ConsecRepDist(A4)
  1306.         Move.L    D0,Channel1+csc_ConsecRepDist(A4)
  1307.         Move.L    D0,Channel2+csc_ConsecRepDist(A4)
  1308.         Move.L    D0,Channel3+csc_ConsecRepDist(A4)
  1309.         Move.L    D3,Channel0+csc_RepeatDist(A4)
  1310.         Move.L    D3,Channel1+csc_RepeatDist(A4)
  1311.         Move.L    D3,Channel2+csc_RepeatDist(A4)
  1312.         Move.L    D3,Channel3+csc_RepeatDist(A4)
  1313.         Move.L    D0,Channel0+csc_SampleStep(A4)
  1314.         Move.L    D0,Channel1+csc_SampleStep(A4)
  1315.         Move.L    D0,Channel2+csc_SampleStep(A4)
  1316.         Move.L    D0,Channel3+csc_SampleStep(A4)
  1317.         Move.W    D0,Channel0+csc_Period(A4)
  1318.         Move.W    D0,Channel1+csc_Period(A4)
  1319.         Move.W    D0,Channel2+csc_Period(A4)
  1320.         Move.W    D0,Channel3+csc_Period(A4)
  1321.         Move.B    D1,Channel0+csc_Volume(A4)
  1322.         Move.B    D1,Channel1+csc_Volume(A4)
  1323.         Move.B    D1,Channel2+csc_Volume(A4)
  1324.         Move.B    D1,Channel3+csc_Volume(A4)
  1325.         Move.L    D2,Channel0+csc_AmplitudeTable(A4)
  1326.         Move.L    D2,Channel1+csc_AmplitudeTable(A4)
  1327.         Move.L    D2,Channel2+csc_AmplitudeTable(A4)
  1328.         Move.L    D2,Channel3+csc_AmplitudeTable(A4)
  1329.  
  1330. ; Render the scopes in their "turned off" state once only...
  1331.  
  1332.         MoveM.L    A5-A6,-(Sp)
  1333.         Bsr    DrawWaveforms
  1334.         Bsr    DrawLeftRight
  1335.         MoveM.L    (Sp)+,A5-A6
  1336.  
  1337.         MoveQ    #0,D7
  1338.         Bra    .NoPlay        ;Skip past code for "playing a song" condition.
  1339.  
  1340.  
  1341. .Playing    Move.B    D7,AlreadyBlankFlag(A4)
  1342.  
  1343.         MoveM.L    A5-A6,-(Sp)
  1344.         Lea    DotStepsTable(A4),A2
  1345.         Lea    ScaleTablePtrs(A4),A5
  1346.         Move.L    DTLBase(A4),A6
  1347.  
  1348. ; Update parameters for each of the four audio channel oscilloscopes...
  1349.  
  1350.         UPDATECHANNEL 0
  1351.         UPDATECHANNEL 1
  1352.         UPDATECHANNEL 2
  1353.         UPDATECHANNEL 3
  1354.  
  1355. ; Render data for all six scopes for this frame...
  1356.  
  1357.         Bsr    DrawWaveforms
  1358.         Bsr    DrawLeftRight
  1359.         MoveM.L    (Sp)+,A5-A6
  1360.  
  1361.         MoveQ    #0,D7    ;Restore D7 since oscilloscope code trashes it.
  1362.  
  1363. ; Here, I have to check for new note hits and update the appropriate channel's
  1364. ; volume bar.  This is a bit more complicated than the pitch bar logic, in that
  1365. ; not only note-hits must be acted upon, but also any change in the channel's
  1366. ; volume as well.  Also, the bar is not simply filled, but instead is filled
  1367. ; only to a height equal to the volume of the channel.  None of this is done
  1368. ; if the channel is disabled...
  1369.  
  1370.         Lea    ChBarHeights+3(A4),A1    ;A1 points to channel bar heights.
  1371.         Lea    ChOldVolumes+4(A4),A0    ;A0 points to old channel volumes.
  1372.         Lea    dtl_Channel3(A5),A2    ;We start with channel 3.
  1373.         Move.B    NewNoteHits(A4),D5    ;D5 holds new note hits.
  1374.  
  1375.         MoveQ    #4-1,D0            ;D0 = loop count and channel #.
  1376.  
  1377. .UpdateChVol    BTst    D0,dtl_Flags+1(A5)    ;Is channel enabled?
  1378.         Beq.S    .NextChVol        ;No, so don't update it.
  1379.  
  1380.         Move.B    cs_RealVolume(A2),D1    ;Get current volume of this channel.
  1381.         Cmp.B    -(A0),D1    ;Has volume changed since last time?
  1382.         Bne    .NewVol        ;Yup, so we must redraw this bar.
  1383.         BTst    D0,D5        ;No, but was there a new note-hit?
  1384.         Beq    .NextChVol    ;Nope. Go on to next channel.
  1385.  
  1386. ; At this point, the bar must be redrawn, either because a new note-hit occurred,
  1387. ; or the channel's volume was changed.  I draw the bar up to a height equal
  1388. ; to the channel's volume, and erase from there to the top of the bar.  Even
  1389. ; though the hardware allows volumes from 0..64 (65 values total), I prefer to
  1390. ; deal in powers of two (programmers go absolutely orgasmic when they see a
  1391. ; power of two)...
  1392.  
  1393. .NewVol        Move.B    cs_RealVolume(A2),D2    ;Get the new channel volume (0..64).
  1394.         Move.B    D2,(A0)            ;Update old volume of this channel.
  1395.         Cmp.B    #63,D2            ;Is it greater than 63?
  1396.         Bls.S    .GoodVol        ;Nope, so it's in range.
  1397.         MoveQ    #$3F,D2            ;Yup, clip to 0..63 range.
  1398. .GoodVol    Move.B    D2,(A1)    ;Yup.        ;Store new height of channel bar.
  1399.  
  1400.         Lea    BOTTOMCVROW(A6),A3    ;A3 points to bottom row.
  1401.         Add.W    D0,A3            ;Add in offset to proper channel bar.
  1402.         Add.W    D0,A3            ;Again 'cause they're 2 bytes apart.
  1403.         MoveQ    #64-1,D2        ;Loop for 64 lines of bar to render.
  1404.         MoveQ    #0,D3            ;D3 counts # of lines drawn in.
  1405.         Move.W    #$7FFC,D4        ;D4 holds data for drawing a bar line.
  1406. .DrawChBar    Move.W    D4,(A3)            ;Draw one line of the channel bar.
  1407.         Lea    -BPBYTESPERROW(A3),A3    ;Move up to next line of bar.
  1408.         Cmp.B    (A0),D3            ;Drawn correct # of lines yet?
  1409.         Beq    .EraseChBar        ;Yes, erase rest of bar to its top.
  1410.         AddQ    #1,D3            ;Nope, increment bar line #.
  1411.         DBra    D2,.DrawChBar        ;And loop to draw another line.
  1412.         Bra    .NextChVol        ;Bar is full, nothing to erase.
  1413.  
  1414. .EraseChBar    Move.W    D7,(A3)            ;Erase a line of the bar.
  1415.         Lea    -BPBYTESPERROW(A3),A3    ;Move up to next bar line.
  1416.         DBra    D2,.EraseChBar        ;Loop for rest of bar's height.
  1417.  
  1418. .NextChVol    Lea    -cs_SIZE(A2),A2        ;A2 points to next channel struct.
  1419.         SubQ.W    #1,A1            ;Next channel's bar height.
  1420.         DBra    D0,.UpdateChVol        ;Loop for all four channels.
  1421.  
  1422. ; Now update the module name field, located at the bottom-middle of the display.
  1423. ; I erase the whole text field if there is no module currently loaded.  If a
  1424. ; module is loaded, then I draw in it's name.  Funny, but for some reason I
  1425. ; render the module name on every vblank.  Isn't life odd sometimes?
  1426.  
  1427. .NoPlay        Lea    CharLookup(PC),A0    ;A0 holds ptr to char lookup table..
  1428.         Lea    MNAMEOFFSET(A6),A1    ;Get ptr to module name field pos.
  1429.         Move.L    dtl_ModuleStatus+ms_Name(A5),A2 ;A2 points to name string.
  1430.  
  1431.         MoveQ    #20-1,D2        ;Initial loop count (20 char cells).
  1432.  
  1433.         Move.B    dtl_Flags(A5),D0
  1434.         Move.B    OldLFlags(A4),D1
  1435.         BTst    #DF_MODULELOADED,dtl_Flags+1(A5)
  1436.         Beq    .EraseMName
  1437.  
  1438. ; Render the module name string as fast as I can.  The characters are each 5 lines
  1439. ; in height, and are aligned on byte boundaries when drawn on screen. I don't use
  1440. ; a loop so the code will execute faster without loop overhead. Also, I use
  1441. ; "Move.B D7,..." instead of Clr.B because the move using a data register as its
  1442. ; source operand is faster than a Clr.B by 4 cycles (Hey, it starts to add up
  1443. ; after a while, ya know ;)...
  1444.  
  1445.         Lea    MNAMEOFFSET(A6),A1    ;Screen address to draw to.
  1446.  
  1447. .DMName        MoveQ    #0,D0            ;Clear out D0.
  1448.         Move.B    (A2)+,D0        ;Fetch a string character.
  1449.         Beq    .EraseMName        ;Reached end of string. Erase rest.
  1450.         Add.W    D0,D0            ;Make longword index out of
  1451.         Add.W    D0,D0            ; ASCII value.
  1452.         Move.L    0(A0,D0.W),A3        ;Use index to obtain char image ptr.
  1453.         Move.B    (A3)+,BPBYTESPERROW*4(A1) ;Draw 5th line of character.
  1454.         Move.B    (A3)+,BPBYTESPERROW*3(A1) ;Draw 4th line.
  1455.         Move.B    (A3)+,BPBYTESPERROW*2(A1) ;Draw 3rd line.
  1456.         Move.B    (A3)+,BPBYTESPERROW*1(A1) ;Draw 2nd line.
  1457.         Move.B    (A3),(A1)+    ;Draw 1st line and advance to next char cell.
  1458.         SubQ    #1,D2        ;One less char cell to be erased.
  1459.         Bmi    .DoneMName    ;20 characters drawn, that's the limit.
  1460.         Bra.S    .DMName        ;Draw chars until end of string reached.
  1461.  
  1462. ; Erase remaining character cells...
  1463.  
  1464. .EraseMName    Move.B    D7,BPBYTESPERROW*4(A1)    ;Erase 5th line of this char cell.
  1465.         Move.B    D7,BPBYTESPERROW*3(A1)    ;Erase 4th line.
  1466.         Move.B    D7,BPBYTESPERROW*2(A1)    ;Erase 3rd line.
  1467.         Move.B    D7,BPBYTESPERROW*1(A1)    ;Erase 2nd line.
  1468.         Move.B    D7,(A1)+    ;Erase 1st line and advance to next char cell.
  1469.         DBra    D2,.EraseMName    ;Loop for remaining character cells.
  1470.  
  1471. .DoneMName    
  1472.  
  1473. ; Now update the elapsed play timer.  This only gets updated if the jiffies
  1474. ; have changed since the last time I checked.  I display elasped hours,
  1475. ; minutes, seconds and jiffies...
  1476.  
  1477.         MoveQ    #0,D0
  1478.         Move.B    dtl_ElapsedJiffies(A5),D0
  1479.         Cmp.B    OldJiffies(A4),D0
  1480.         Beq    .DoneTimer        ;Nope, don't update.
  1481.         Lea    CharLookup(PC),A0    ;Cache lookup table ptr in A0.
  1482.         Lea    TIMEROFFSET+9(A6),A1    ;Yup, get display offset.
  1483.         Move.B    D0,OldJiffies(A4)    ;Update the jiffies variable.
  1484.         Bsr    Print2Digits
  1485.         Move.B    dtl_ElapsedSeconds(A5),D0
  1486.         Lea    TIMEROFFSET+6(A6),A1
  1487.         Bsr    Print2Digits
  1488.         Move.B    dtl_ElapsedMinutes(A5),D0
  1489.         Lea    TIMEROFFSET+3(A6),A1
  1490.         Bsr    Print2Digits
  1491.         Move.B    dtl_ElapsedHours(A5),D0
  1492.         Lea    TIMEROFFSET(A6),A1
  1493.         Bsr    Print2Digits
  1494. .DoneTimer
  1495.  
  1496. ; Now I have to check each instrument name and draw or erase each text
  1497. ; field as necessary in much the same way as I handled the module name text.
  1498. ; However, here I have to draw in the instrument name, and then erase the rest
  1499. ; of the text field to make sure that no characters from the old instrument
  1500. ; name remain left behind. This routine uses lots of address registers...
  1501.  
  1502.         MoveM.L    A4/A5/A6,-(Sp)        ;I need the extra registers, so...
  1503.         MoveQ    #4-1,D0            ;Loop once for each sound channel.
  1504.         Lea    dtl_Channel0(A5),A0    ;A0 points to first channel struct.
  1505.         Lea    OldInsts(A4),A1        ;A1 points to old channel inst ptrs table.
  1506.         Lea    INAMEOFFSET(A6),A2    ;Screen ptr to channel 0 inst name pos.
  1507.         Lea    CharLookup(PC),A4    ;Careful use of my sacred register!
  1508.         Move.B    dtl_Flags+1(A5),D3    ;Get copy of flags field.
  1509.  
  1510. .DoINames    Move.L    cs_Instrument(A0),A3    ;Get ptr to channel 0 instrument.
  1511.  
  1512.         MoveQ    #22-1,D1        ;Prepare for loop to draw 22 chars.
  1513.         Move.L    A2,A5            ;Keep original pointer in A2.
  1514.  
  1515.         BTst    D0,D3            ;Is this channel enabled?
  1516.         Beq    .EraseIName        ;Nope.
  1517.  
  1518.         Cmp.L    (A1),A3            ;Has instrument changed?
  1519.         Beq    .NextIName        ;Nope, move on to next channel.
  1520.  
  1521.         Move.L    A3,(A1)            ;Update old channel inst pointer.
  1522.         Beq    .EraseIName        ;A3 holds 0. No instrument is used.
  1523.  
  1524.         Move.L    is_Name(A3),A3        ;Extract inst name pointer to A3.
  1525.  
  1526. .DrawIName    MoveQ    #0,D2            ;Make sure D2 is clear.
  1527.         Move.B    (A3)+,D2        ;Get a char from inst name string.
  1528.         Beq    .EraseIName        ;Reached end of string. Done.
  1529.         Add.W    D2,D2            ;Make a longword index from
  1530.         Add.W    D2,D2            ; the ASCII char value.
  1531.         Move.L    0(A4,D2.W),A6        ;Get character image ptr in A6.
  1532.         Move.B    (A6)+,BPBYTESPERROW*4(A5) ;Draw 5th line of character.
  1533.         Move.B    (A6)+,BPBYTESPERROW*3(A5) ;Draw 4th line.
  1534.         Move.B    (A6)+,BPBYTESPERROW*2(A5) ;Draw 3rd line.
  1535.         Move.B    (A6)+,BPBYTESPERROW*1(A5) ;Draw 2nd line.
  1536.         Move.B    (A6),(A5)+    ;Draw first line and advance to next cell.
  1537.         DBra    D1,.DrawIName    ;Loop for rest of string.
  1538.         Bra    .NextIName    ;No cells left to erase. Next channel...
  1539.  
  1540. ; Erase any remaining character cells if the instrument name was less than
  1541. ; 22 characters in length...
  1542.  
  1543. .EraseIName    Move.B    D7,BPBYTESPERROW*4(A5)    ;Erase 5th line of character cell.
  1544.         Move.B    D7,BPBYTESPERROW*3(A5)    ;Erase 4th line.
  1545.         Move.B    D7,BPBYTESPERROW*2(A5)    ;Erase 3rd line.
  1546.         Move.B    D7,BPBYTESPERROW*1(A5)    ;Erase 2nd line.
  1547.         Move.B    D7,(A5)+    ;Erase 1st line and advance to next cell.
  1548.         DBra    D1,.EraseIName    ;Loop for remaining character cells.
  1549.  
  1550. .NextIName    AddQ    #4,A1            ;Next old channel instrument ptr.
  1551.         Lea    cs_SIZE(A0),A0        ;Next sound channel.
  1552.         Lea    INAMEDISTANCE(A2),A2    ;Move to next inst text field area.
  1553.         DBra    D0,.DoINames        ;Loop for all four sound channels.
  1554.  
  1555. .DoneINames    MoveM.L    (Sp)+,A4/A5/A6    ;Restore the registers I trashed.
  1556.  
  1557. ; Hey, hey, now it's time to render the fake left/right peak meter displays.
  1558. ; If the new left output is greater than the current value that I have, then
  1559. ; I display the new left output level.  Otherwise, I decrease the old level
  1560. ; a bit.  Then I do the same for the right output.
  1561. ;
  1562. ; The rendering code for the left/right peak meters is totally gross, IMHO.
  1563.  
  1564.         MoveQ    #0,D0
  1565.  
  1566.         BTst    #DF_PLAYING,dtl_Flags+1(A5) ;Is a song currently playing?
  1567.         Beq    .NoNewLeft        ;No, no new left peak meter level.
  1568.  
  1569.         Move.B    LeftOutput(A4),D0    ;Get left output level (0..16).
  1570.         Add.B    D0,D0
  1571.         Add.B    D0,D0
  1572.         Cmp.B    LeftLevel(A4),D0
  1573.         Blt.S    .NoNewLeft
  1574.  
  1575.         Move.B    D0,LeftLevel(A4)
  1576.  
  1577. .NoNewLeft    Move.B    LeftLevel(A4),D0    ;Nope, don't change a thing.
  1578.  
  1579. ; Now I render the left peak meter.  WARNING:  This code is REALLY ugly...
  1580.  
  1581. .NewLeftLevel    AddQ    #7,D0
  1582.         MoveQ    #8-1,D1            ;Loop for eight meter "lights".
  1583.         MoveQ    #0,D3
  1584.         Move.L    Plane0Addr(A4),A2
  1585.         Move.L    Plane1Addr(A4),A3
  1586.         Lea    LEFTOFFSET(A6),A0    ;Get ptr to first meter "light" pos.
  1587.         Lea    LEFTOFFSET(A2),A2
  1588.         Lea    LEFTOFFSET(A3),A3
  1589.         Move.W    #$7FFC,D2        ;Value used to render "lights".
  1590.         Move.W    #$8003,D4
  1591.         Lsr.W    #3,D0            ;Divide by 8 to get 0..7 (1..8 lights).
  1592.         Beq    .EraseLeft        ;=0 means vol. too low to register.
  1593.  
  1594. .DrawLeft    Cmp.W    #7,D3
  1595.         Blt    .NotRedL
  1596.         Or.W    D2,BPBYTESPERROW(A2)
  1597.         Or.W    D2,(A2)
  1598.         And.W    D4,BPBYTESPERROW(A3)
  1599.         And.W    D4,(A3)
  1600.         Bra    .SkipYellowL
  1601. .NotRedL    Cmp.W    #6,D3
  1602.         Blt    .SkipYellowL
  1603.         Or.W    D2,BPBYTESPERROW(A2)
  1604.         Or.W    D2,(A2)
  1605. .SkipYellowL    Move.W    D2,BPBYTESPERROW(A0)    ;Draw 2nd line of "light".
  1606.         Move.W    D2,(A0)+        ;Draw 1st and advance to next "light".
  1607.         AddQ.W    #2,A2
  1608.         AddQ.W    #2,A3
  1609.         AddQ    #1,D3
  1610.         SubQ    #1,D0            ;Decrement light counter.
  1611.         Beq    .EraseLeft        ;"Turn off" remaining "lights".
  1612.         DBra    D1,.DrawLeft        ;Else loop for "lights" that are on.
  1613.         Bra    .DoneLeft        ;No "lights" left to be erased.
  1614.  
  1615. .EraseLeft    Move.W    RestoreP0(A4),D2
  1616.         Move.W    RestoreP1(A4),D3
  1617.         Bra    .DoErL
  1618. .EraseL        Move.W    D2,BPBYTESPERROW(A2)
  1619.         Move.W    D2,(A2)+
  1620.         Move.W    D3,BPBYTESPERROW(A3)
  1621.         Move.W    D3,(A3)+
  1622.         Move.W    D7,BPBYTESPERROW(A0)    ;Erase 2nd line of "light".
  1623.         Move.W    D7,(A0)+        ;Erase 1st and advance to next "light".
  1624. .DoErL        DBra    D1,.EraseL        ;Loop for remaining lights.
  1625.  
  1626. .DoneLeft    SubQ.B    #2,LeftLevel(A4)    ;Reduce meter level a little at a time.
  1627.         Bpl    .DoRight        ;There's still some volume left.
  1628.         Clr.B    LeftLevel(A4)        ;Meter level wrapped, so clear it.
  1629.  
  1630.  
  1631. ; Well, now we do EXACTLY the same thing for the right peak meter, except that
  1632. ; we examine channels 0 and 3 instead of 1 and 2...
  1633.  
  1634. .DoRight    MoveQ    #0,D0
  1635.  
  1636.         BTst    #DF_PLAYING,dtl_Flags+1(A5) ;Is a song currently playing?
  1637.         Beq    .NoNewRight        ;No, no new right peak meter level.
  1638.  
  1639.         Move.B    RightOutput(A4),D0    ;Get right output level (0..16).
  1640.         Add.B    D0,D0
  1641.         Add.B    D0,D0
  1642.         Cmp.B    RightLevel(A4),D0
  1643.         Blt.S    .NoNewRight
  1644.  
  1645.         Move.B    D0,RightLevel(A4)
  1646.  
  1647. .NoNewRight    Move.B    RightLevel(A4),D0    ;Nope, don't change a thing.
  1648.  
  1649. ; Now I render the left peak meter.  WARNING:  This code is REALLY ugly...
  1650.  
  1651. .NewRightLevel    AddQ    #7,D0
  1652.         MoveQ    #8-1,D1            ;Loop for eight meter "lights".
  1653.         MoveQ    #0,D3
  1654.         Move.L    Plane0Addr(A4),A2
  1655.         Move.L    Plane1Addr(A4),A3
  1656.         Lea    RIGHTOFFSET(A6),A0    ;Get ptr to first meter "light" pos.
  1657.         Lea    RIGHTOFFSET(A2),A2
  1658.         Lea    RIGHTOFFSET(A3),A3
  1659.         Move.W    #$7FFC,D2        ;Value used to render "lights".
  1660.         Move.W    #$8003,D4
  1661.         Lsr.W    #3,D0            ;Divide by 2 to get 0..7 (1..8 lights).
  1662.         Beq    .EraseRight        ;=0 means vol. too low to register.
  1663.  
  1664. .DrawRight    Cmp.W    #7,D3
  1665.         Blt    .NotRedR
  1666.         Or.W    D2,BPBYTESPERROW(A2)
  1667.         Or.W    D2,(A2)
  1668.         And.W    D4,BPBYTESPERROW(A3)
  1669.         And.W    D4,(A3)
  1670.         Bra    .SkipYellowR
  1671. .NotRedR    Cmp.W    #6,D3
  1672.         Blt    .SkipYellowR
  1673.         Or.W    D2,BPBYTESPERROW(A2)
  1674.         Or.W    D2,(A2)
  1675. .SkipYellowR    Move.W    D2,BPBYTESPERROW(A0)    ;Draw 2nd line of "light".
  1676.         Move.W    D2,(A0)+        ;Draw 1st and advance to next "light".
  1677.         AddQ.W    #2,A2
  1678.         AddQ    #2,A3
  1679.         AddQ    #1,D3
  1680.         SubQ    #1,D0            ;Decrement light counter.
  1681.         Beq    .EraseRight        ;"Turn off" remaining "lights".
  1682.         DBra    D1,.DrawRight        ;Else loop for "lights" that are on.
  1683.         Bra    .DoneRight        ;No "lights" left to be erased.
  1684.  
  1685. .EraseRight    Move.W    RestoreP0(A4),D2
  1686.         Move.W    RestoreP1(A4),D3
  1687.         Bra    .DoErR
  1688. .EraseR        Move.W    D2,BPBYTESPERROW(A2)
  1689.         Move.W    D2,(A2)+
  1690.         Move.W    D3,BPBYTESPERROW(A3)
  1691.         Move.W    D3,(A3)+
  1692.         Move.W    D7,BPBYTESPERROW(A0)    ;Erase 2nd line of "light".
  1693.         Move.W    D7,(A0)+        ;Erase 1st and advance to next "light".
  1694. .DoErR        DBra    D1,.EraseR        ;Loop for remaining lights.
  1695.  
  1696. .DoneRight    SubQ.B    #2,RightLevel(A4)    ;Reduce meter level a little at a time.
  1697.         Bpl    .DoneRightBar        ;There's still some volume left.
  1698.         Clr.B    RightLevel(A4)        ;Meter level wrapped, so clear it.
  1699. .DoneRightBar
  1700.  
  1701. ; Now it's time to update the numerical statistics. i.e. the values that must be
  1702. ; converted to decimal strings and rendered to the display.  I decided to use a
  1703. ; subroutine to convert and print the values, even though it costs me 34 cycles
  1704. ; for every BSR and RTS instruction pair (Grrr), but duplicating the conversion/
  1705. ; print code for each value to be rendered is a bit much.  I consoled myself by
  1706. ; writing a PIG of a decimal string conversion routine (it uses three 256 byte
  1707. ; lookup tables. YeeeHAAA!).  But hell, is it fast.  Kinda makes up for the
  1708. ; urine-like peak-meter code. :)
  1709.  
  1710.         Lea    CharLookup(PC),A0    ;Cache lookup table ptr in A0.
  1711.         MoveQ    #0,D0            ;Clear out that register!
  1712.  
  1713.         Move.B    dtl_GlobalVolume(A5),D0    ;Get current global volume.
  1714.         Cmp.B    OldGlobalVolume(A4),D0    ;Has it changed since last time?
  1715.         Beq    .DoneGVolume        ;Nope, don't update it then.
  1716.         Move.B    D0,OldGlobalVolume(A4)    ;Yes, update variable.
  1717.         Lea    GVOLOFFSET(A6),A1    ;Load up screen dest for text.
  1718.         Bsr    PrintByte        ;Convert value to string and print.
  1719. .DoneGVolume
  1720.  
  1721. ; Dealing with the global tempo is a bit diffrerent, since it's a signed value.
  1722. ; If the global tempo is negative, I manually print a "-" sign, then negate the
  1723. ; value, making it positive, then convert and print that...
  1724.  
  1725.         Move.B    dtl_GlobalTempo(A5),D0    ;Get current global tempo.
  1726.         Cmp.B    OldGlobalTempo(A4),D0    ;Has it changed?
  1727.         Beq    .DoneGTempo        ;Nope.
  1728.         Lea    GTEMPOOFFSET(A6),A1    ;Yup, get dest addr for text.
  1729.         Move.B    D7,BPBYTESPERROW*2(A1)    ;Erase spot for "-" char.
  1730.         Move.B    D0,OldGlobalTempo(A4)    ;Update old variable.
  1731.         Bpl    .PrintGT        ;New tempo is positive.
  1732.         Neg.B    D0            ;Oop, it's negative, make it pos.
  1733.         MoveQ    #$7E,D1
  1734.         Move.B    D1,BPBYTESPERROW*2(A1)    ; and draw in the "-" sign.
  1735. .PrintGT    AddQ    #1,A1            ;Advance to next char. cell.
  1736.         Bsr    PrintByte        ;Convert value to string and print it.
  1737. .DoneGTempo
  1738.  
  1739. ; Now do much the same thing for the global fine tempo...
  1740.  
  1741.         Move.B    dtl_FineTempo(A5),D0    ;Get current fine tempo.
  1742.         Cmp.B    OldFineTempo(A4),D0    ;Has it changed?
  1743.         Beq    .DoneFTempo        ;Nope.
  1744.         Lea    FINETEMPOOFFSET(A6),A1    ;Yup, get dest addr for text.
  1745.         Move.B    D7,BPBYTESPERROW*2(A1)    ;Erase spot for "-" char.
  1746.         Move.B    D0,OldFineTempo(A4)    ;Update old variable.
  1747.         Bpl    .PrintFT        ;New tempo is positive.
  1748.         Neg.B    D0            ;Oop, it's negative, make it pos.
  1749.         MoveQ    #$7E,D1
  1750.         Move.B    D1,BPBYTESPERROW*2(A1)    ; and draw in the "-" sign.
  1751. .PrintFT    AddQ    #1,A1            ;Advance to next char. cell.
  1752.         Bsr    PrintByte        ;Convert value to string and print it.
  1753. .DoneFTempo
  1754.  
  1755. ; Now display the current hertz...
  1756.  
  1757.         Move.L    dtl_CurrentHertz(A5),D2    ;Get current playback freq.
  1758.         Cmp.L    OldCurHertz(A4),D2    ;Has it changed?
  1759.         Beq    .DoneCurrentHz        ;Nope.
  1760.  
  1761.         Move.L    D2,OldCurHertz(A4)    ;Update old variable.
  1762.  
  1763.         Move.L    D2,D0
  1764.         Clr.W    D0
  1765.         Swap    D0
  1766.         And.W    #$FF,D0
  1767.  
  1768.         MulU    #100,D2
  1769.         Add.L    #$8000,D2
  1770.         Clr.W    D2
  1771.         Swap    D2
  1772.         Cmp.B    #99,D2
  1773.         Ble    .FracHzOK
  1774.  
  1775.         Sub.B    #100,D2
  1776.         AddQ    #1,D0
  1777.  
  1778. .FracHzOK    And.W    #$FF,D2
  1779.         Lea    HERTZOFFSET(A6),A1    ;Yup, get dest addr for integer.
  1780.         Bsr    PrintByte        ;Print integer part of Hz.
  1781.  
  1782.         Move.L    D2,D0
  1783.         Lea    HERTZOFFSET+4(A6),A1    ;Yup, get dest addr for fraction.
  1784.         Bsr    Print2Digits        ;Print fractional part of Hz.
  1785. .DoneCurrentHz
  1786.  
  1787.         Move.B    dtl_Iterations(A5),D0    ;Get current # of iterations.
  1788.         Cmp.B    OldNumIters(A4),D0    ;Has it changed?
  1789.         Beq    .DoneNumIters        ;Nope.
  1790.         Move.B    D0,OldNumIters(A4)    ;Yup, update variable contents.
  1791.         Lea    NITEROFFSET(A6),A1    ;Get ptr to dest screen position.
  1792.         Bsr    PrintByte        ;Convert and print new value.
  1793. .DoneNumIters
  1794.  
  1795.         Move.B    dtl_IterationsToGo(A5),D0 ;Get current # of iterations left.
  1796.         Cmp.B    OldItersToGo(A4),D0    ;Has it changed?
  1797.         Beq    .DoneItersToGo        ;Nope.
  1798.         Move.B    D0,OldItersToGo(A4)    ;Yup, update it for next time.
  1799.         Lea    LITEROFFSET(A6),A1    ;Get ptr to screen position.
  1800.         Bsr    PrintByte        ;Convert and print the new value.
  1801. .DoneItersToGo
  1802.  
  1803. ; The rest of the stats that require conversion to decimal strings are valid
  1804. ; only when a module is loaded.  If no module is loaded, then I write "---" in
  1805. ; place of these stats, since they cannot have legitimate values.  I even have
  1806. ; a special subroutine just for printing "---" at a specified screen location :)
  1807.  
  1808.         BTst    #DF_MODULELOADED,dtl_Flags+1(A5) ;Is a module loaded?
  1809.         Bne    .IsAModule        ;Yup, check for value updating.
  1810.  
  1811.         Tst.B    DrawNAFlag(A4)        ;Have we already cleared stats?
  1812.         Bne    .DoneModStats        ;Yup, once is enough.
  1813.  
  1814.         St    DrawNAFlag(A4)        ;Set one-shot update flag.
  1815.  
  1816.         Lea    CURTEMPOOFFSET(A6),A1    ;Screen pos. for current tempo.
  1817.         Bsr    PrintNA            ;Print "---".
  1818.         Lea    CURPOSOFFSET(A6),A1    ;Screen pos. for current position.
  1819.         Bsr    PrintNA
  1820.         Lea    SPOSOFFSET(A6),A1    ;Screen pos. for start position.
  1821.         Bsr    PrintNA
  1822.         Lea    EPOSOFFSET(A6),A1    ;Screen pos. for end position.
  1823.         Bsr    PrintNA
  1824.         Lea    CNOTEOFFSET(A6),A1    ;Screen pos. for current note index.
  1825.         Bsr    PrintNA
  1826.         Lea    SNOTEOFFSET(A6),A1    ;Screen pos. for start note index.
  1827.         Bsr    PrintNA
  1828.         Lea    ENOTEOFFSET(A6),A1    ;Screen pos. for end note index.
  1829.         Bsr    PrintNA
  1830.  
  1831. ; Now I prime these stats so that as soon as a module is loaded, all of them
  1832. ; will be instantly updated on screen (since they are then assumed to be valid
  1833. ; because a module is now loaded, the vblank will not re-render them (eliminating
  1834. ; the "---") unless the contents have changed).  So...
  1835.  
  1836.         MoveQ    #-1,D0
  1837.         Move.B    D0,OldCurrentTempo(A4)    ;Prime these stats for
  1838.         Move.B    D0,OldCurPosition(A4)    ; when a new module is loaded.
  1839.         Move.B    D0,OldStartPos(A4)
  1840.         Move.B    D0,OldEndPos(A4)
  1841.         Move.B    D0,OldCurNote(A4)
  1842.         Move.B    D0,OldStartNote(A4)
  1843.         Move.B    D0,OldEndNote(A4)
  1844.         Bra    .DoneModStats        ;Skip the proper update logic.
  1845.  
  1846. ; The following bits of code are so repetitive that I couldn't bring myself
  1847. ; to comment them.  Essentially, each little code-unit checks to see if a given
  1848. ; parameter has changed and re-renders it if it has...
  1849.  
  1850.  
  1851. .IsAModule    Move.B    D7,DrawNAFlag(A4)
  1852.  
  1853.         Move.B    dtl_CurrentTempo(A5),D0
  1854.         Cmp.B    OldCurrentTempo(A4),D0
  1855.         Beq    .DoneCurTempo
  1856.         Move.B    D0,OldCurrentTempo(A4)
  1857.         Lea    CURTEMPOOFFSET(A6),A1
  1858.         Bsr    PrintByte
  1859. .DoneCurTempo
  1860.  
  1861.         Move.B    dtl_CurPosition(A5),D0
  1862.         Cmp.B    OldCurPosition(A4),D0
  1863.         Beq    .DoneCPosition
  1864.         Move.B    D0,OldCurPosition(A4)
  1865.         Lea    CURPOSOFFSET(A6),A1
  1866.         Bsr    PrintByte
  1867. .DoneCPosition
  1868.  
  1869.         Move.B    dtl_StartPosition(A5),D0
  1870.         Cmp.B    OldStartPos(A4),D0
  1871.         Beq    .DoneStartPos
  1872.         Move.B    D0,OldStartPos(A4)
  1873.         Lea    SPOSOFFSET(A6),A1
  1874.         Bsr    PrintByte
  1875. .DoneStartPos
  1876.  
  1877.         Move.B    dtl_EndPosition(A5),D0
  1878.         Cmp.B    OldEndPos(A4),D0
  1879.         Beq    .DoneEndPos
  1880.         Move.B    D0,OldEndPos(A4)
  1881.         Lea    EPOSOFFSET(A6),A1
  1882.         Bsr    PrintByte
  1883. .DoneEndPos
  1884.  
  1885.         Move.B    dtl_CurNoteIndex(A5),D0
  1886.         Cmp.B    OldCurNote(A4),D0
  1887.         Beq    .DoneCurNote
  1888.         Move.B    D0,OldCurNote(A4)
  1889.         Lea    CNOTEOFFSET(A6),A1
  1890.         Bsr    PrintByte
  1891. .DoneCurNote
  1892.  
  1893.         Move.B    dtl_StartNoteIndex(A5),D0
  1894.         Cmp.B    OldStartNote(A4),D0
  1895.         Beq    .DoneStartNote
  1896.         Move.B    D0,OldStartNote(A4)
  1897.         Lea    SNOTEOFFSET(A6),A1
  1898.         Bsr    PrintByte
  1899. .DoneStartNote
  1900.  
  1901.         Move.B    dtl_EndNoteIndex(A5),D0
  1902.         Cmp.B    OldEndNote(A4),D0
  1903.         Beq    .DoneEndNote
  1904.         Move.B    D0,OldEndNote(A4)
  1905.         Lea    ENOTEOFFSET(A6),A1
  1906.         Bsr    PrintByte
  1907. .DoneEndNote
  1908. .DoneModStats
  1909.  
  1910. ; Lastly update the status text field if necessary...
  1911.  
  1912.         MoveQ    #0,D0
  1913.         Move.B    dtl_PlayStatus(A5),D0
  1914.         Cmp.B    OldStatus(A4),D0
  1915.         Beq    .DoneStatus
  1916.         Move.B    D0,OldStatus(A4)
  1917.         Add.W    D0,D0
  1918.         Add.W    D0,D0
  1919.         Lea    StatusPtrs(PC),A0
  1920.         Move.L    0(A0,D0.W),A0
  1921.         Lea    CharLookup(PC),A1
  1922.         Lea    STATUSOFFSET(A6),A2
  1923.  
  1924. .DrawStatus    MoveQ    #0,D1
  1925.         Move.B    (A0)+,D1
  1926.         Beq    .DoneStatus
  1927.         Add.W    D1,D1
  1928.         Add.W    D1,D1
  1929.         Move.L    0(A1,D1.W),A3
  1930.         Move.B    (A3)+,BPBYTESPERROW*4(A2)
  1931.         Move.B    (A3)+,BPBYTESPERROW*3(A2)
  1932.         Move.B    (A3)+,BPBYTESPERROW*2(A2)
  1933.         Move.B    (A3)+,BPBYTESPERROW*1(A2)
  1934.         Move.B    (A3),(A2)+
  1935.         Bra.S    .DrawStatus
  1936. .DoneStatus
  1937.         
  1938.  
  1939. .LeaveVB    MoveM.L    (Sp)+,D0-D7/A2-A6
  1940.         Rts
  1941.  
  1942. ;------------------------------
  1943.  
  1944. DrawWaveforms    Move.L    A4,-(Sp)
  1945.  
  1946.         Lea    Channel0(A4),A0
  1947.         Lea    YVert(PC),A3
  1948.         MoveQ    #4-1,D4
  1949.  
  1950. ChannelLoop    Lea    csc_Amplitudes(A0),A4
  1951.         Move.L    csc_AmplitudeTable(A0),A6
  1952.         Move.L    csc_ScreenBaseAddr(A0),A5
  1953.         MoveQ    #8-1,D6
  1954.         Move.W    csc_Frac(A0),D0
  1955.         Move.W    csc_SampleStep+2(A0),D1
  1956.         Move.W    csc_SampleStep(A0),D5
  1957.         Move.L    csc_CurSamplePtr(A0),A1
  1958.         Move.L    csc_SampleEnd(A0),D2
  1959.         Lea    csc_OldPositions(A0),A2
  1960.  
  1961. ; One macro invocation for each pixel in the oscilloscope...
  1962.  
  1963.         DRAWCHDOT 1
  1964.         DRAWCHDOT 2
  1965.         DRAWCHDOT 3
  1966.         DRAWCHDOT 4
  1967.         DRAWCHDOT 5
  1968.         DRAWCHDOT 6
  1969.         DRAWCHDOT 7
  1970.         DRAWCHDOT 8
  1971.         DRAWCHDOT 9
  1972.         DRAWCHDOT 10
  1973.         DRAWCHDOT 11
  1974.         DRAWCHDOT 12
  1975.         DRAWCHDOT 13
  1976.         DRAWCHDOT 14
  1977.         DRAWCHDOT 15
  1978.         DRAWCHDOT 16
  1979.         DRAWCHDOT 17
  1980.         DRAWCHDOT 18
  1981.         DRAWCHDOT 19
  1982.         DRAWCHDOT 20
  1983.         DRAWCHDOT 21
  1984.         DRAWCHDOT 22
  1985.         DRAWCHDOT 23
  1986.         DRAWCHDOT 24
  1987.         DRAWCHDOT 25
  1988.         DRAWCHDOT 26
  1989.         DRAWCHDOT 27
  1990.         DRAWCHDOT 28
  1991.         DRAWCHDOT 29
  1992.         DRAWCHDOT 30
  1993.         DRAWCHDOT 31
  1994.         DRAWCHDOT 32
  1995.  
  1996. ; Save parameters updated dynamically by the above macro invocations...
  1997.  
  1998.         Move.L    A1,csc_CurSamplePtr(A0)
  1999.         Move.L    D2,csc_SampleEnd(A0)
  2000.         Move.W    D0,csc_Frac(A0)
  2001.  
  2002. ; Next audio channel oscilloscope...
  2003.  
  2004.         Lea    csc_SIZEOF(A0),A0
  2005.         DBra    D4,ChannelLoop
  2006.  
  2007.         Move.L    (Sp)+,A4
  2008.         Rts
  2009.  
  2010. ;------------------------------
  2011. ; This routine renders the left and right total output oscilloscopes.
  2012. ; It also calculates left and right output "voltage" for the peak meter
  2013. ; displays...
  2014.  
  2015. DrawLeftRight    Lea    Channel0(A4),A0
  2016.         Lea    csc_Amplitudes(A0),A0
  2017.         Lea    Channel3(A4),A1
  2018.         Lea    csc_Amplitudes(A1),A1
  2019.         Lea    OldLeftAmplitudes(A4),A2
  2020.         Move.L    LeftScreenAddrP0(A4),A3
  2021.         Move.L    LeftScreenAddrP1(A4),A6
  2022.         Lea    YVert(PC),A5
  2023.         MoveQ    #-2,D0    ;Used as mask ($FFFE)
  2024.  
  2025.         MoveQ    #8-1,D3
  2026.  
  2027. ; One macro invocation for each pixel in the oscilloscope...
  2028.  
  2029.         DRAWLRDOT 1
  2030.         DRAWLRDOT 2
  2031.         DRAWLRDOT 3
  2032.         DRAWLRDOT 4
  2033.         DRAWLRDOT 5
  2034.         DRAWLRDOT 6
  2035.         DRAWLRDOT 7
  2036.         DRAWLRDOT 8
  2037.         DRAWLRDOT 9
  2038.         DRAWLRDOT 10
  2039.         DRAWLRDOT 11
  2040.         DRAWLRDOT 12
  2041.         DRAWLRDOT 13
  2042.         DRAWLRDOT 14
  2043.         DRAWLRDOT 15
  2044.         DRAWLRDOT 16
  2045.         DRAWLRDOT 17
  2046.         DRAWLRDOT 18
  2047.         DRAWLRDOT 19
  2048.         DRAWLRDOT 20
  2049.         DRAWLRDOT 21
  2050.         DRAWLRDOT 22
  2051.         DRAWLRDOT 23
  2052.         DRAWLRDOT 24
  2053.         DRAWLRDOT 25
  2054.         DRAWLRDOT 26
  2055.         DRAWLRDOT 27
  2056.         DRAWLRDOT 28
  2057.         DRAWLRDOT 29
  2058.         DRAWLRDOT 30
  2059.         DRAWLRDOT 31
  2060.         DRAWLRDOT 32
  2061.  
  2062. DrawRight    Lea    Channel1(A4),A0
  2063.         Lea    csc_Amplitudes(A0),A0
  2064.         Lea    Channel2(A4),A1
  2065.         Lea    csc_Amplitudes(A1),A1
  2066.         Lea    OldRightAmplitudes(A4),A2
  2067.         Move.L    RightScreenAddrP0(A4),A3
  2068.         Move.L    RightScreenAddrP1(A4),A6
  2069.  
  2070.         MoveQ    #8-1,D3
  2071.  
  2072. ; One macro invocation for each pixel in the oscilloscope...
  2073.  
  2074.         DRAWLRDOT 1
  2075.         DRAWLRDOT 2
  2076.         DRAWLRDOT 3
  2077.         DRAWLRDOT 4
  2078.         DRAWLRDOT 5
  2079.         DRAWLRDOT 6
  2080.         DRAWLRDOT 7
  2081.         DRAWLRDOT 8
  2082.         DRAWLRDOT 9
  2083.         DRAWLRDOT 10
  2084.         DRAWLRDOT 11
  2085.         DRAWLRDOT 12
  2086.         DRAWLRDOT 13
  2087.         DRAWLRDOT 14
  2088.         DRAWLRDOT 15
  2089.         DRAWLRDOT 16
  2090.         DRAWLRDOT 17
  2091.         DRAWLRDOT 18
  2092.         DRAWLRDOT 19
  2093.         DRAWLRDOT 20
  2094.         DRAWLRDOT 21
  2095.         DRAWLRDOT 22
  2096.         DRAWLRDOT 23
  2097.         DRAWLRDOT 24
  2098.         DRAWLRDOT 25
  2099.         DRAWLRDOT 26
  2100.         DRAWLRDOT 27
  2101.         DRAWLRDOT 28
  2102.         DRAWLRDOT 29
  2103.         DRAWLRDOT 30
  2104.         DRAWLRDOT 31
  2105.         DRAWLRDOT 32
  2106.  
  2107. ; Before leaving, Compute the left and right output levels for the peak
  2108. ; meter displays.  I tried several different algorithms here in an attempt
  2109. ; to more accurately simulate real peak meter output (I didn't just know how
  2110. ; to do it because I'm not an audio engineer).  The algorithm below is the
  2111. ; one I finally settled on.
  2112. ;
  2113. ; The way it works: Since (to the best of my knowledge) a real peak meter
  2114. ; displays output voltage in decibels, the algorithm below treats each output
  2115. ; sample for a scope as a "voltage level".  A sample value of 0 means "0 volts".
  2116. ; Now, the left output level for the current frame is determined by first
  2117. ; taking the 32 (or NDOTS) output samples from the channel 0 scope, obtaining
  2118. ; the absolute value for each sample, and averaging them together.  This
  2119. ; effectively yields the average sustained "voltage" for the current frame for
  2120. ; audio channel #0's output.  The same calcs are then done for channel #3 (the
  2121. ; other left output channel).  Once this is done, the two resulting "voltage"
  2122. ; averages are compared, and the higher of the two values is used.
  2123. ;
  2124. ; The same thing is done with channels #1 and #2 for the right output.
  2125. ;
  2126. ; In some cases there is a loss of accuracy (because not all samples played
  2127. ; for the current frame are considered; only the samples that are actually
  2128. ; displayed on the screen. The number of samples played per frame is typically
  2129. ; a lot higher than the number of samples displayed per frame).
  2130. ;
  2131. ; Despite this occasional inaccuracy, I have found that the left/right peak
  2132. ; meters in LScope now behave surprisingly like real peak meters.  In fact, I
  2133. ; have compared LScope's peak meter display to the peak meters on my tape
  2134. ; deck, and I was quite surprised at just how accurate LScope's peak meters
  2135. ; are.  The only problem is, LScope is stuck at one "recording level" whereas
  2136. ; I can change the level on my tape deck.  Oh well...
  2137.  
  2138.         Lea    Channel0+csc_Amplitudes(A4),A0
  2139.         Lea    Channel3+csc_Amplitudes(A4),A1
  2140.         Lea    Channel1+csc_Amplitudes(A4),A2
  2141.         Lea    Channel2+csc_Amplitudes(A4),A3
  2142.  
  2143.         MoveQ    #0,D1
  2144.         MoveQ    #0,D2
  2145.         MoveQ    #0,D3
  2146.         MoveQ    #0,D4
  2147.         MoveQ    #0,D5
  2148.  
  2149.         MoveQ    #NDOTS-1,D0
  2150.  
  2151. .Loop        Move.B    (A0)+,D1 ;Get "voltage" output for channel #1.
  2152.         Bpl.S    .1
  2153.         Neg.B    D1    ;Make it positive (i.e. distance from "0 volts").
  2154. .1        Add.W    D1,D2    ;Accumulate channel #1 "voltage" output.
  2155.  
  2156.         Move.B    (A1)+,D1 ;Do same for channel #2.
  2157.         Bpl.S    .2
  2158.         Neg.B    D1
  2159. .2        Add.W    D1,D3
  2160.  
  2161.         Move.B    (A2)+,D1 ;Do same for channel #0.
  2162.         Bpl.S    .3
  2163.         Neg.B    D1
  2164. .3        Add.W    D1,D4
  2165.  
  2166.         Move.B    (A3)+,D1 ;Do same for channel #3.
  2167.         Bpl.S    .4
  2168.         Neg.B    D1
  2169. .4        Add.W    D1,D5
  2170.  
  2171.         DBra    D0,.Loop ;Loop for NDOTS samples from each channel.
  2172.  
  2173.         Cmp.W    D2,D3    ;Is channel #3 output higher than channel #0?
  2174.         Ble.S    .5    ;Nope.
  2175.         Exg    D2,D3    ;Yes, I want highest left output in D2.
  2176.  
  2177. .5        Cmp.W    D4,D5    ;Is channel #2 output higher than channel #1?
  2178.         Ble.S    .6    ;Nope.
  2179.         Exg    D4,D5    ;Yes, I want highest right output in D4.
  2180.  
  2181. .6        Add.W    D3,D2
  2182.         Add.W    D5,D4
  2183.         Lsr.W    #1,D2
  2184.         Lsr.W    #1,D4
  2185.  
  2186.         Lsr.W    #5,D2    ;Obtain average left output.
  2187.         Lsr.W    #5,D4    ;Obtain average right output.
  2188.  
  2189.         Move.B    D2,LeftOutput(A4)    ;Store left output for this frame.
  2190.         Move.B    D4,RightOutput(A4)    ;Store right output for this frame.
  2191.  
  2192.         Rts
  2193.  
  2194. ;------------------------------
  2195. ; LScopeVBlank routine.  This is the vertical blank service routine for the
  2196. ; L-Scope program.  It simply signals the main code each time the VBlank occurs.
  2197. ; It also notifies the main code whenever the VBlank frequency changes (also
  2198. ; via signalling).
  2199. ;
  2200. ;    Input: A1 = Pointer to L-Scope variables (supplied by operating system).
  2201. ;
  2202. LScopeVBlank    MoveM.L    D1/A0-A1/A4/A6,-(Sp)
  2203.  
  2204.         Move.L    A1,A4        ;A4 is my sacred address register. :)
  2205.  
  2206.         LOADLIB    SYS
  2207.         Bsr    CalcVBlankFrequency
  2208.         Move.B    D0,D1
  2209.         MoveQ    #0,D0
  2210.         Cmp.B    CurVBFreq(A4),D1
  2211.         Beq    .NoVBChange
  2212.  
  2213.         Move.B    D1,CurVBFreq(A4)
  2214.  
  2215.         Move.B    VBSigBit(A4),D1
  2216.         BSet    D1,D0
  2217.  
  2218. .NoVBChange    Move.B    RedrawSigBit(A4),D1
  2219.         BSet    D1,D0
  2220.  
  2221.         Move.L    LScopeTaskPtr(A4),A1
  2222.         SYS    Signal
  2223.  
  2224.         MoveM.L    (Sp)+,D1/A0-A1/A4/A6
  2225.         MoveQ    #0,D0
  2226.         Rts
  2227.  
  2228. ;------------------------------
  2229. ; This routine prints a three digit numerical string to the screen. It's
  2230. ; pretty damn fast (at some expense of memory, of course), considering it
  2231. ; converts a byte value into a three digit decimal string AND renders it
  2232. ; to the screen in only 368 cycles. If you call the routine at the "Print2Digits"
  2233. ; entry point, it will make a 2 digit decimal string and render the string all in
  2234. ; only 248 cycles.  Yowsa!  Note that I could have improved the speed even more
  2235. ; by making the HunsLookup, TensLookup, and OnesLookup tables into longword tables
  2236. ; holding pointers directly to the character images themselves, but the increase
  2237. ; in speed would be negligible compared to the increase in memory requirements
  2238. ; that would be necessary to pull it off.  Know when to draw the line, I always
  2239. ; say (FYI, I'd only drop about 42 cycles from the speed of this routine by doing
  2240. ; such a modification, but the lookup tables would grow from 768 bytes to 3072).
  2241. ; I could also save 34 cycles (the overhead of a BSR/RTS instruction pair) by
  2242. ; repeating this whole routine everywhere I call it, but then the listing would
  2243. ; start gettin' a wee bit long and tedious, so I figured, "...Not!".  =)
  2244. ;
  2245. ;    Input:    D0.W = Byte value to be converted and displayed.
  2246. ;        A0   = Pointer to CharLookup table.
  2247. ;        A1   = Pointer to dest screen area to draw digits.
  2248. ;
  2249.                                                   ;Cycles (68000)
  2250. PrintByte       MoveQ   #0,D1                     ;  4   ;Make sure D1 is clear.
  2251.                 Lea     HunsLookup(PC),A3         ;  8   ;Get ptr to hundreds digits table.
  2252.                 Move.B  0(A3,D0.W),D1             ; 14   ;Get the hundreds digit index.
  2253.                 Move.L  0(A0,D1.W),A3             ; 18   ;Get pointer to char image.
  2254.                 Move.B  (A3)+,BPBYTESPERROW*4(A1) ; 16   ;Draw 5th line of char.
  2255.                 Move.B  (A3)+,BPBYTESPERROW*3(A1) ; 16   ;Draw 4th line.
  2256.                 Move.B  (A3)+,BPBYTESPERROW*2(A1) ; 16   ;Draw 3rd line.
  2257.                 Move.B  (A3)+,BPBYTESPERROW*1(A1) ; 16   ;Draw 2nd line.
  2258.                 Move.B  (A3),(A1)+                ; 12   ;Draw 1st. next char cell.
  2259.  
  2260. Print2Digits    MoveQ   #0,D1                     ;  4   ;Clear D1 for this entry point.
  2261.                 Lea     TensLookup(PC),A3         ;  8   ;Get ptr to tens digit table.
  2262.                 Move.B  0(A3,D0.W),D1             ; 14   ;Get tens digit index.
  2263.                 Move.L  0(A0,D1.W),A3             ; 18   ;Get ptr to char image.
  2264.                 Move.B  (A3)+,BPBYTESPERROW*4(A1) ; 16   ;Draw 5th line of char.
  2265.                 Move.B  (A3)+,BPBYTESPERROW*3(A1) ; 16   ;Draw 4th line.
  2266.                 Move.B  (A3)+,BPBYTESPERROW*2(A1) ; 16   ;Draw 3rd line.
  2267.                 Move.B  (A3)+,BPBYTESPERROW*1(A1) ; 16   ;Draw 2nd line.
  2268.                 Move.B  (A3),(A1)+                ; 12   ;Draw 1st, next char cell.
  2269.  
  2270.                 Move.B  OnesLookup(PC,D0.W),D1    ; 18   ;Get ones digit index.
  2271.                 Move.L  0(A0,D1.W),A3             ; 18   ;Get ptr to char image.
  2272.                 Move.B  (A3)+,BPBYTESPERROW*4(A1) ; 16   ;Draw 5th line of char.
  2273.                 Move.B  (A3)+,BPBYTESPERROW*3(A1) ; 16   ;Draw 4th line.
  2274.                 Move.B  (A3)+,BPBYTESPERROW*2(A1) ; 16   ;Draw 3rd line.
  2275.                 Move.B  (A3)+,BPBYTESPERROW*1(A1) ; 16   ;Draw 2nd line.
  2276.                 Move.B  (A3),(A1)                 ; 12   ;Draw 1st line. All done!
  2277.  
  2278.                 Rts                               ; 16   ;An RTS! Grrrr!
  2279.                                                   ;---
  2280.                                                   ;368 cycles total
  2281. ;------------------------------
  2282. ; This routine prints "---" at the screen area pointed at by A1. It is used
  2283. ; for values that are meaningless under certain circumstances (like the
  2284. ; number of patterns in a module when there is no module loaded, for example).
  2285. ; I unwound it a bit to make it faster, since the loop code would be quite small,
  2286. ; and the overhead for 3 loop iterations amounts to an increase of 38 cycles.
  2287. ; Unwinding it didn't cost me much memory, so I figured, "What the hell...".
  2288. ; This routine takes 188 cycles to render "---" at the screen dest in A1.
  2289. ; (It would only take 52 cycles if I didn't have to erase the whole character
  2290. ; cell).
  2291. ;
  2292. ;       Input: A1 = Pointer to screen dest area, which will get trashed.
  2293. ;              D7 = 0
  2294. ;
  2295.                                                   ;Cycles;(68000)
  2296. PrintNA         MoveQ   #$7E,D0                   ;  4   ;Image of "-" sign.
  2297.  
  2298.                 Move.B  D7,BPBYTESPERROW*4(A1)    ; 12   ;Erase 5th line of cell.
  2299.                 Move.B  D7,BPBYTESPERROW*3(A1)    ; 12   ;Erase 4th line.
  2300.                 Move.B  D0,BPBYTESPERROW*2(A1)    ; 12   ;Draw "-" to 3rd line.
  2301.                 Move.B  D7,BPBYTESPERROW*1(A1)    ; 12   ;Erase 2nd line.
  2302.                 Move.B  D7,(A1)+                  ;  8   ;Erase 1st, next char cell.
  2303.  
  2304.                 Move.B  D7,BPBYTESPERROW*4(A1)    ; 12   ;Erase 5th line of cell.
  2305.                 Move.B  D7,BPBYTESPERROW*3(A1)    ; 12   ;Erase 4th line.
  2306.                 Move.B  D0,BPBYTESPERROW*2(A1)    ; 12   ;Draw "-" to 3rd line.
  2307.                 Move.B  D7,BPBYTESPERROW*1(A1)    ; 12   ;Erase 2nd line.
  2308.                 Move.B  D7,(A1)+                  ;  8   ;Erase 1st, next char cell.
  2309.  
  2310.                 Move.B  D7,BPBYTESPERROW*4(A1)    ; 12   ;Erase 5th line of cell.
  2311.                 Move.B  D7,BPBYTESPERROW*3(A1)    ; 12   ;Erase 4th line.
  2312.                 Move.B  D0,BPBYTESPERROW*2(A1)    ; 12   ;Draw "-" to 3rd line.
  2313.                 Move.B  D7,BPBYTESPERROW*1(A1)    ; 12   ;Erase 2nd line.
  2314.                 Move.B  D7,(A1)                   ;  8   ;Erase 1st line.
  2315.  
  2316.                 Rts                               ; 16   ;All done.
  2317.                                                   ;---
  2318.                                                   ;188 cycles total.
  2319.  
  2320. ;---------------------------------------------------------------
  2321. ; I hate to do this, but, as Chris Crawford once said: "Damn!  I need a REALLY
  2322. ; fast binary to decimal conversion routine!" ( Hey, if Chris Crawford can do
  2323. ; it, then so can I. :).  These three tables are used by the PrintByte routine.
  2324. ; Each table is indexed by the byte value to be converted to a decimal string
  2325. ; and rendered, and each table contains offset values into the CharLookup table
  2326. ; for acquiring a ptr to the character image to draw (The values in this table
  2327. ; are pre-shifted left twice to create a longword index from the ASCII digits
  2328. ; "0" to "9" (i.e. $30 ("0") shifted left twice (multiplied by four) yields
  2329. ; $C0, "1" yields $C1, etc).  Fortunately for me, the shifted offsets still fit
  2330. ; in a byte, but just barely.
  2331. ;
  2332. ; Seriously, I got the idea for using these tables from Chris Crawford.  In fact,
  2333. ; I saw a similar binary to decimal conversion routine (using tables like those
  2334. ; below) in Mr. Crawford's source code for Eastern Front 1941 for the 8-bit Atari
  2335. ; many many years ago.  Chris Crawford was my programming idol until he sold out
  2336. ; and moved to IBM-Land.  Oh Chris, why hast thou forsaken me...
  2337.  
  2338. OnesLookup
  2339.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2340.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2341.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2342.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2343.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2344.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2345.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2346.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2347.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2348.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2349.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2350.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4
  2351.  Dc.B    $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC,$E0,$E4,$C0,$C4,$C8,$CC,$D0,$D4
  2352.  
  2353. TensLookup
  2354.  Dc.B    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4
  2355.  Dc.B    $C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
  2356.  Dc.B    $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4
  2357.  Dc.B    $D8,$D8,$D8,$D8,$D8,$D8,$D8,$D8,$D8,$D8,$DC,$DC,$DC,$DC,$DC,$DC,$DC,$DC,$DC,$DC
  2358.  Dc.B    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E4,$E4,$E4,$E4,$E4,$E4,$E4,$E4,$E4,$E4
  2359.  Dc.B    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4
  2360.  Dc.B    $C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
  2361.  Dc.B    $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4,$D4
  2362.  Dc.B    $D8,$D8,$D8,$D8,$D8,$D8,$D8,$D8,$D8,$D8,$DC,$DC,$DC,$DC,$DC,$DC,$DC,$DC,$DC,$DC
  2363.  Dc.B    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E4,$E4,$E4,$E4,$E4,$E4,$E4,$E4,$E4,$E4
  2364.  Dc.B    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4
  2365.  Dc.B    $C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
  2366.  Dc.B    $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0,$D4,$D4,$D4,$D4,$D4,$D4
  2367.  
  2368. HunsLookup
  2369.  Dc.B    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0
  2370.  Dc.B    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0
  2371.  Dc.B    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0
  2372.  Dc.B    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0
  2373.  Dc.B    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0
  2374.  Dc.B    $C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4
  2375.  Dc.B    $C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4
  2376.  Dc.B    $C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4
  2377.  Dc.B    $C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4
  2378.  Dc.B    $C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4,$C4
  2379.  Dc.B    $C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8
  2380.  Dc.B    $C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8
  2381.  Dc.B    $C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8,$C8
  2382.  
  2383.  
  2384. ;------------------------------
  2385. ; Scan line delta table.  Holds screen memory offsets of n scan lines...
  2386. ; This lookup table flips the delta Y on the X axis so that negative
  2387. ; amplitudes are displayed in the bottom half of the scope and positive
  2388. ; amplitudes in the upper half...
  2389.  
  2390.         Dc.W    BPBYTESPERROW*16
  2391.         Dc.W    BPBYTESPERROW*15
  2392.         Dc.W    BPBYTESPERROW*14
  2393.         Dc.W    BPBYTESPERROW*13
  2394.         Dc.W    BPBYTESPERROW*12
  2395.         Dc.W    BPBYTESPERROW*11
  2396.         Dc.W    BPBYTESPERROW*10
  2397.         Dc.W    BPBYTESPERROW*9
  2398.         Dc.W    BPBYTESPERROW*8
  2399.         Dc.W    BPBYTESPERROW*7
  2400.         Dc.W    BPBYTESPERROW*6
  2401.         Dc.W    BPBYTESPERROW*5
  2402.         Dc.W    BPBYTESPERROW*4
  2403.         Dc.W    BPBYTESPERROW*3
  2404.         Dc.W    BPBYTESPERROW*2
  2405.         Dc.W    BPBYTESPERROW*1
  2406.         Dc.W    BPBYTESPERROW*0
  2407. YVert        Dc.W    BPBYTESPERROW*-1
  2408.         Dc.W    BPBYTESPERROW*-2
  2409.         Dc.W    BPBYTESPERROW*-3
  2410.         Dc.W    BPBYTESPERROW*-4
  2411.         Dc.W    BPBYTESPERROW*-5
  2412.         Dc.W    BPBYTESPERROW*-6
  2413.         Dc.W    BPBYTESPERROW*-7
  2414.         Dc.W    BPBYTESPERROW*-8
  2415.         Dc.W    BPBYTESPERROW*-9
  2416.         Dc.W    BPBYTESPERROW*-10
  2417.         Dc.W    BPBYTESPERROW*-11
  2418.         Dc.W    BPBYTESPERROW*-12
  2419.         Dc.W    BPBYTESPERROW*-13
  2420.         Dc.W    BPBYTESPERROW*-14
  2421.         Dc.W    BPBYTESPERROW*-15
  2422.         Dc.W    BPBYTESPERROW*-16
  2423.         Dc.W    BPBYTESPERROW*-17
  2424.  
  2425. ;------------------------------
  2426. ; Base clock constant lookup table for North American Amigas.
  2427. ; Covers base constants for VBlank frequencies in the
  2428. ; range 30..80Hz.
  2429. ;
  2430. ; Formula per longword element i:
  2431. ;
  2432. ; Table[i] = TRUNC((((3579545/(i+30))/2)*256)+0.5)
  2433.  
  2434. BaseNAmerica    Dc.L    $00E90B15    ;30Hz
  2435.         Dc.L    $00E18699    ;31Hz
  2436.         Dc.L    $00DA7A64    ;32Hz
  2437.         Dc.L    $00D3DB88    ;33Hz
  2438.         Dc.L    $00CDA05E    ;34Hz
  2439.         Dc.L    $00C7C05B    ;35Hz
  2440.         Dc.L    $00C233E7    ;36Hz
  2441.         Dc.L    $00BCF436    ;37Hz
  2442.         Dc.L    $00B7FB47    ;38Hz
  2443.         Dc.L    $00B3439A    ;39Hz
  2444.         Dc.L    $00AEC850    ;40Hz
  2445.         Dc.L    $00AA84FD    ;41Hz
  2446.         Dc.L    $00A675A2    ;42Hz
  2447.         Dc.L    $00A2969E    ;43Hz
  2448.         Dc.L    $009EE4A6    ;44Hz
  2449.         Dc.L    $009B5CB9    ;45Hz
  2450.         Dc.L    $0097FC19    ;46Hz
  2451.         Dc.L    $0094C044    ;47Hz
  2452.         Dc.L    $0091A6ED    ;48Hz
  2453.         Dc.L    $008EADF8    ;49Hz
  2454.         Dc.L    $008BD373    ;50Hz
  2455.         Dc.L    $00891594    ;51Hz
  2456.         Dc.L    $008672B4    ;52Hz
  2457.         Dc.L    $0083E94B    ;53Hz
  2458.         Dc.L    $008177EF    ;54Hz
  2459.         Dc.L    $007F1D51    ;55Hz
  2460.         Dc.L    $007CD839    ;56Hz
  2461.         Dc.L    $007AA784    ;57Hz
  2462.         Dc.L    $00788A26    ;58Hz
  2463.         Dc.L    $00767F21    ;59Hz
  2464.         Dc.L    $0074858B    ;60Hz
  2465.         Dc.L    $00729C88    ;61Hz
  2466.         Dc.L    $0070C34C    ;62Hz
  2467.         Dc.L    $006EF916    ;63Hz
  2468.         Dc.L    $006D3D32    ;64Hz
  2469.         Dc.L    $006B8EF6    ;65Hz
  2470.         Dc.L    $0069EDC4    ;66Hz
  2471.         Dc.L    $00685906    ;67Hz
  2472.         Dc.L    $0066D02F    ;68Hz
  2473.         Dc.L    $006552BB    ;69Hz
  2474.         Dc.L    $0063E02E    ;70Hz
  2475.         Dc.L    $00627810    ;71Hz
  2476.         Dc.L    $006119F4    ;72Hz
  2477.         Dc.L    $005FC56E    ;73Hz
  2478.         Dc.L    $005E7A1D    ;74Hz
  2479.         Dc.L    $005D37A2    ;75Hz
  2480.         Dc.L    $005BFDA3    ;76Hz
  2481.         Dc.L    $005ACBCC    ;77Hz
  2482.         Dc.L    $0059A1CD    ;78Hz
  2483.         Dc.L    $00587F59    ;79Hz
  2484.         Dc.L    $00576428    ;80Hz
  2485.  
  2486. ;------------------------------
  2487. ; Base clock constant lookup table for European Amigas.
  2488. ; Covers base frequency constants for VBlank frequencies in the
  2489. ; range 30..80.
  2490. ;
  2491. ; Formula per longword element i:
  2492. ;
  2493. ; Table[i] = TRUNC((((3546895/(i+30))/2)*256)+0.5)
  2494.  
  2495. BaseEurope    Dc.L    $00E6EAEB    ;30Hz
  2496.         Dc.L    $00DF77FC    ;31Hz
  2497.         Dc.L    $00D87C3C    ;32Hz
  2498.         Dc.L    $00D1ECD5    ;33Hz
  2499.         Dc.L    $00CBC038    ;34Hz
  2500.         Dc.L    $00C5EDEE    ;35Hz
  2501.         Dc.L    $00C06E6E    ;36Hz
  2502.         Dc.L    $00BB3B03    ;37Hz
  2503.         Dc.L    $00B64DAC    ;38Hz
  2504.         Dc.L    $00B1A103    ;39Hz
  2505.         Dc.L    $00AD3030    ;40Hz
  2506.         Dc.L    $00A8F6D1    ;41Hz
  2507.         Dc.L    $00A4F0F1    ;42Hz
  2508.         Dc.L    $00A11AF7    ;43Hz
  2509.         Dc.L    $009D71A0    ;44Hz
  2510.         Dc.L    $0099F1F2    ;45Hz
  2511.         Dc.L    $00969935    ;46Hz
  2512.         Dc.L    $009364ED    ;47Hz
  2513.         Dc.L    $009052D3    ;48Hz
  2514.         Dc.L    $008D60CE    ;49Hz
  2515.         Dc.L    $008A8CF3    ;50Hz
  2516.         Dc.L    $0087D57B    ;51Hz
  2517.         Dc.L    $008538C2    ;52Hz
  2518.         Dc.L    $0082B546    ;53Hz
  2519.         Dc.L    $0080499F    ;54Hz
  2520.         Dc.L    $007DF480    ;55Hz
  2521.         Dc.L    $007BB4B5    ;56Hz
  2522.         Dc.L    $0079891D    ;57Hz
  2523.         Dc.L    $007770AE    ;58Hz
  2524.         Dc.L    $00756A6F    ;59Hz
  2525.         Dc.L    $00737575    ;60Hz
  2526.         Dc.L    $007190E9    ;61Hz
  2527.         Dc.L    $006FBBFE    ;62Hz
  2528.         Dc.L    $006DF5F6    ;63Hz
  2529.         Dc.L    $006C3E1E    ;64Hz
  2530.         Dc.L    $006A93CF    ;65Hz
  2531.         Dc.L    $0068F66B    ;66Hz
  2532.         Dc.L    $0067655E    ;67Hz
  2533.         Dc.L    $0065E01C    ;68Hz
  2534.         Dc.L    $00646623    ;69Hz
  2535.         Dc.L    $0062F6F7    ;70Hz
  2536.         Dc.L    $00619222    ;71Hz
  2537.         Dc.L    $00603737    ;72Hz
  2538.         Dc.L    $005EE5CD    ;73Hz
  2539.         Dc.L    $005D9D82    ;74Hz
  2540.         Dc.L    $005C5DF7    ;75Hz
  2541.         Dc.L    $005B26D6    ;76Hz
  2542.         Dc.L    $0059F7C9    ;77Hz
  2543.         Dc.L    $0058D082    ;78Hz
  2544.         Dc.L    $0057B0B4    ;79Hz
  2545.         Dc.L    $00569818    ;80Hz
  2546.  
  2547. ;------------------------------
  2548.  
  2549. ScanlineSteps    Dc.L    $0000,$0000,$1000,$1000,$1000,$2000,$2000,$2000
  2550.         Dc.L    $2000,$3000,$3000,$3000,$3000,$4000,$4000,$4000
  2551.         Dc.L    $4000,$5000,$5000,$5000,$5000,$6000,$6000,$6000
  2552.         Dc.L    $6000,$7000,$7000,$7000,$7000,$8000,$8000,$8000
  2553.         Dc.L    $8000,$9000,$9000,$9000,$9000,$A000,$A000,$A000
  2554.         Dc.L    $A000,$B000,$B000,$B000,$B000,$C000,$C000,$C000
  2555.         Dc.L    $C000,$D000,$D000,$D000,$D000,$E000,$E000,$E000
  2556.         Dc.L    $E000,$F000,$F000,$F000,$F000,$10000,$10000,$10000
  2557.         Dc.L    $10000
  2558.  
  2559. ;------------------------------
  2560.  
  2561. ScanlineStarts    Dc.B    0,0,-1,-1,-1,-2,-2,-2,-2,-3,-3,-3,-3,-4,-4,-4,-4
  2562.         Dc.B    -5,-5,-5,-5,-6,-6,-6,-6,-7,-7,-7,-7,-8,-8,-8,-8
  2563.         Dc.B    -9,-9,-9,-9,-10,-10,-10,-10,-11,-11,-11,-11
  2564.         Dc.B    -12,-12,-12,-12,-13,-13,-13,-13,-14,-14,-14,-14
  2565.         Dc.B    -15,-15,-15,-15,-16,-16,-16,-16
  2566.         Even
  2567.  
  2568. ;------------------------------
  2569.  
  2570. BlankSample    Dc.L    0    ;Used when no sample is playing in a channel.
  2571.  
  2572. ;------------------------------
  2573. ; This is the NEWSCREEN structure for creating the screen that L-Scope uses...
  2574.  
  2575. MyNewScreen    Dc.W    0                ;WORD ns_LeftEdge
  2576.         Dc.W    0                ;WORD ns_TopEdge
  2577.         Dc.W    320                ;WORD ns_Width
  2578.         Dc.W    210                ;WORD ns_Height
  2579.         Dc.W    3                ;WORD ns_Depth
  2580.         Dc.B    1                ;BYTE ns_DetailPen
  2581.         Dc.B    0                ;BYTE ns_BlockPen
  2582.         Dc.W    0                ;WORD ns_ViewModes
  2583.         Dc.W    CUSTOMSCREEN|SCREENBEHIND    ;WORD ns_Type
  2584.         Dc.L    TopazFontAttr            ;APTR ns_Font
  2585.         Dc.L    MyTitle                ;APTR ns_DefaultTitle
  2586.         Dc.L    0                ;APTR ns_Gadgets
  2587.         Dc.L    0                ;APTR ns_CustomBitMap
  2588.  
  2589.  
  2590. ; This is the NEWWINDOW structure for creating the window that L-Scope uses...
  2591.  
  2592. MyNewWindow    Dc.W    0        ;WORD nw_LeftEdge
  2593.         Dc.W    10        ;WORD nw_TopEdge
  2594.         Dc.W    320        ;WORD nw_Width
  2595.         Dc.W    200        ;WORD nw_Height
  2596.         Dc.B    1        ;BYTE nw_DetailPen
  2597.         Dc.B    0        ;BYTE nw_BlockPen
  2598.         Dc.L    MYIDCMP        ;LONG nw_IDCMPFlags
  2599.         Dc.L    MYWFLAGS    ;LONG nw_Flags
  2600.         Dc.L    0        ;APTR nw_FirstGadget
  2601.         Dc.L    0        ;APTR nw_CheckMark
  2602.         Dc.L    0        ;APTR nw_Title
  2603. NWScreen    Dc.L    0        ;APTR nw_Screen (not good for pure code!)
  2604.         Dc.L    0        ;APTR nw_BitMap
  2605.         Dc.W    0        ;WORD nw_MinWidth
  2606.         Dc.W    0        ;WORD nw_MinHeight
  2607.         Dc.W    0        ;WORD nw_MaxWidth
  2608.         Dc.W    0        ;WORD nw_MaxHeight
  2609.         Dc.W    CUSTOMSCREEN    ;WORD nw_Type
  2610.                     ;LABEL nw_SIZE
  2611.  
  2612. ; This is the text attribute structure for use with my screen...
  2613.  
  2614. TopazFontAttr    Dc.L    TopazName
  2615.         Dc.W    TOPAZ_EIGHTY
  2616.         Dc.B    FS_NORMAL
  2617.         Dc.B    FPF_ROMFONT
  2618.  
  2619. TopazName    Dc.B    "topaz.font",0
  2620.         Even
  2621.  
  2622. ; The following table is used for looking up screen raster line positions at
  2623. ; which to draw/erase pieces of the channel volume bars (typically the topmost
  2624. ; line of the blue part of the bar)...
  2625.  
  2626. ChannelOffsets    Dc.W    COBASE+(63*BPBYTESPERROW)
  2627.         Dc.W    COBASE+(62*BPBYTESPERROW)
  2628.         Dc.W    COBASE+(61*BPBYTESPERROW)
  2629.         Dc.W    COBASE+(60*BPBYTESPERROW)
  2630.         Dc.W    COBASE+(59*BPBYTESPERROW)
  2631.         Dc.W    COBASE+(58*BPBYTESPERROW)
  2632.         Dc.W    COBASE+(57*BPBYTESPERROW)
  2633.         Dc.W    COBASE+(56*BPBYTESPERROW)
  2634.         Dc.W    COBASE+(55*BPBYTESPERROW)
  2635.         Dc.W    COBASE+(54*BPBYTESPERROW)
  2636.         Dc.W    COBASE+(53*BPBYTESPERROW)
  2637.         Dc.W    COBASE+(52*BPBYTESPERROW)
  2638.         Dc.W    COBASE+(51*BPBYTESPERROW)
  2639.         Dc.W    COBASE+(50*BPBYTESPERROW)
  2640.         Dc.W    COBASE+(49*BPBYTESPERROW)
  2641.         Dc.W    COBASE+(48*BPBYTESPERROW)
  2642.         Dc.W    COBASE+(47*BPBYTESPERROW)
  2643.         Dc.W    COBASE+(46*BPBYTESPERROW)
  2644.         Dc.W    COBASE+(45*BPBYTESPERROW)
  2645.         Dc.W    COBASE+(44*BPBYTESPERROW)
  2646.         Dc.W    COBASE+(43*BPBYTESPERROW)
  2647.         Dc.W    COBASE+(42*BPBYTESPERROW)
  2648.         Dc.W    COBASE+(41*BPBYTESPERROW)
  2649.         Dc.W    COBASE+(40*BPBYTESPERROW)
  2650.         Dc.W    COBASE+(39*BPBYTESPERROW)
  2651.         Dc.W    COBASE+(38*BPBYTESPERROW)
  2652.         Dc.W    COBASE+(37*BPBYTESPERROW)
  2653.         Dc.W    COBASE+(36*BPBYTESPERROW)
  2654.         Dc.W    COBASE+(35*BPBYTESPERROW)
  2655.         Dc.W    COBASE+(34*BPBYTESPERROW)
  2656.         Dc.W    COBASE+(33*BPBYTESPERROW)
  2657.         Dc.W    COBASE+(32*BPBYTESPERROW)
  2658.         Dc.W    COBASE+(31*BPBYTESPERROW)
  2659.         Dc.W    COBASE+(30*BPBYTESPERROW)
  2660.         Dc.W    COBASE+(29*BPBYTESPERROW)
  2661.         Dc.W    COBASE+(28*BPBYTESPERROW)
  2662.         Dc.W    COBASE+(27*BPBYTESPERROW)
  2663.         Dc.W    COBASE+(26*BPBYTESPERROW)
  2664.         Dc.W    COBASE+(25*BPBYTESPERROW)
  2665.         Dc.W    COBASE+(24*BPBYTESPERROW)
  2666.         Dc.W    COBASE+(23*BPBYTESPERROW)
  2667.         Dc.W    COBASE+(22*BPBYTESPERROW)
  2668.         Dc.W    COBASE+(21*BPBYTESPERROW)
  2669.         Dc.W    COBASE+(20*BPBYTESPERROW)
  2670.         Dc.W    COBASE+(19*BPBYTESPERROW)
  2671.         Dc.W    COBASE+(18*BPBYTESPERROW)
  2672.         Dc.W    COBASE+(17*BPBYTESPERROW)
  2673.         Dc.W    COBASE+(16*BPBYTESPERROW)
  2674.         Dc.W    COBASE+(15*BPBYTESPERROW)
  2675.         Dc.W    COBASE+(14*BPBYTESPERROW)
  2676.         Dc.W    COBASE+(13*BPBYTESPERROW)
  2677.         Dc.W    COBASE+(12*BPBYTESPERROW)
  2678.         Dc.W    COBASE+(11*BPBYTESPERROW)
  2679.         Dc.W    COBASE+(10*BPBYTESPERROW)
  2680.         Dc.W    COBASE+(09*BPBYTESPERROW)
  2681.         Dc.W    COBASE+(08*BPBYTESPERROW)
  2682.         Dc.W    COBASE+(07*BPBYTESPERROW)
  2683.         Dc.W    COBASE+(06*BPBYTESPERROW)
  2684.         Dc.W    COBASE+(05*BPBYTESPERROW)
  2685.         Dc.W    COBASE+(04*BPBYTESPERROW)
  2686.         Dc.W    COBASE+(03*BPBYTESPERROW)
  2687.         Dc.W    COBASE+(02*BPBYTESPERROW)
  2688.         Dc.W    COBASE+(01*BPBYTESPERROW)
  2689.         Dc.W    COBASE+(00*BPBYTESPERROW)
  2690.  
  2691.  
  2692. ; The values in this table are actually pointers to the last row of the
  2693. ; corresponding character image.  The reason I do this is because I use
  2694. ; pre-decrement on the address register that points to the character
  2695. ; image (I draw it from the bottom up), and so the addr register must point
  2696. ; to the last byte of the character image that I want to render...
  2697.  
  2698. CharLookup    
  2699.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2700.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2701.  Dc.L    C01,C02,C03,C04,C05,C06,C07,C08,C09,C10,C11,C12,C13,C14,C15,C16
  2702.  Dc.L    C17,C18,C19,C20,C21,C22,C23,C24,C25,C26,C27,C28,C29,C30,C31,C32
  2703.  Dc.L    C33,C34,C35,C36,C37,C38,C39,C40,C41,C42,C43,C44,C45,C46,C47,C48
  2704.  Dc.L    C49,C50,C51,C52,C53,C54,C55,C56,C57,C58,C59,C60,C61,C62,C63,C64
  2705.  Dc.L    C65,C34,C35,C36,C37,C38,C39,C40,C41,C42,C43,C44,C45,C46,C47,C48
  2706.  Dc.L    C49,C50,C51,C52,C53,C54,C55,C56,C57,C58,C59,C66,C66,C66,C66,C66
  2707.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2708.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2709.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2710.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2711.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2712.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2713.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2714.  Dc.L    C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66,C66
  2715.  
  2716.  
  2717. ; Pointer table for looking up the address of the status text that I want to
  2718. ; print.  I use the top 3 bits of the low byte of dtl_Flags as my index (shifted
  2719. ; down to bits 0..2 of course)...
  2720.  
  2721. StatusPtrs    Dc.L    NoModText
  2722.         Dc.L    IdleText
  2723.         Dc.L    PlayingText
  2724.         Dc.L    PausedText
  2725.         Dc.L    StoppedText
  2726.         Dc.L    PSDoneText
  2727.  
  2728. ; The 8-color palette for my 3-plane display...
  2729.  
  2730. PicPalette    Dc.W    $444,$777,$000,$AAA,$66F,$F00,$0F0,$FF0
  2731.  
  2732. ; Library name strings for OpenLibrary...
  2733.  
  2734. IntName        Dc.B    "intuition.library",0
  2735. GfxName        Dc.B    "graphics.library",0
  2736. DTLName        DTLIBNAME
  2737.  
  2738. ; The name of my vertical blank routine (and message port)...
  2739.  
  2740. ProgName    Dc.B    "L-Scope",0
  2741. VBlankName    Dc.B    "L-Scope VBL",0
  2742.  
  2743. ; The text for my screen's title bar...
  2744.  
  2745. MyTitle        Dc.B    "L-Scope 2.0 by D. E. Schebek",0
  2746.  
  2747. ;==============================
  2748.  
  2749.         DATA
  2750.         Even
  2751.  
  2752. ; Here are the images of all the characters I need to render from time to time.
  2753. ; Each character is one byte wide by five bytes tall (occupying...uh... 5 bytes
  2754. ; each!).  The first character is the space character, and they proceed in ASCII
  2755. ; order all the way up to the reverse apostrophe character (including an "illegal
  2756. ; char" character image at the very end).  You may notice that all of these images
  2757. ; are upside-down.  Well, this is because they are drawn from the bottom up (so
  2758. ; that the last line can automatically advance to the next character cell to the
  2759. ; right at the same time), but I want to use post-increment to draw the chars,
  2760. ; since a post-increment MOVE.B is 2 cycles faster than a pre-decrement MOVE.B.
  2761. ; Like I said before, all these little cycles add up after a while...
  2762.  
  2763. C01    Dc.B    %00000000    ;Space character.
  2764.     Dc.B    %00000000
  2765.     Dc.B    %00000000
  2766.     Dc.B    %00000000
  2767.     Dc.B    %00000000
  2768.  
  2769. C02    Dc.B    %00011000    ;' ! '
  2770.     Dc.B    %00000000
  2771.     Dc.B    %00011000
  2772.     Dc.B    %00011000
  2773.     Dc.B    %00011000
  2774.  
  2775. C03    Dc.B    %00000000    ;' " '
  2776.     Dc.B    %00000000
  2777.     Dc.B    %00000000
  2778.     Dc.B    %01101100
  2779.     Dc.B    %01101100
  2780.  
  2781. C04    Dc.B    %01101100    ;' # '
  2782.     Dc.B    %11111110
  2783.     Dc.B    %01101100
  2784.     Dc.B    %11111110
  2785.     Dc.B    %01101100
  2786.  
  2787. C05    Dc.B    %01111100    ;' $ '
  2788.     Dc.B    %00010110
  2789.     Dc.B    %01111000
  2790.     Dc.B    %11010000
  2791.     Dc.B    %01111100
  2792.  
  2793. C06    Dc.B    %01100110    ;' % '
  2794.     Dc.B    %00110110
  2795.     Dc.B    %00011000
  2796.     Dc.B    %01101100
  2797.     Dc.B    %01100110
  2798.  
  2799. C07    Dc.B    %00111100    ;' & '
  2800.     Dc.B    %01101110
  2801.     Dc.B    %00110000
  2802.     Dc.B    %00011000
  2803.     Dc.B    %00011000
  2804.  
  2805. C08    Dc.B    %00000000    ;' ' '
  2806.     Dc.B    %00000000
  2807.     Dc.B    %00000000
  2808.     Dc.B    %00011000
  2809.     Dc.B    %00011000
  2810.  
  2811. C09    Dc.B    %00000110    ;' ( '
  2812.     Dc.B    %00001100
  2813.     Dc.B    %00001100
  2814.     Dc.B    %00001100
  2815.     Dc.B    %00000110
  2816.  
  2817. C10    Dc.B    %01100000    ;' ) '
  2818.     Dc.B    %00110000
  2819.     Dc.B    %00110000
  2820.     Dc.B    %00110000
  2821.     Dc.B    %01100000
  2822.  
  2823. C11    Dc.B    %01010100    ;' * '
  2824.     Dc.B    %00111000
  2825.     Dc.B    %11111110
  2826.     Dc.B    %00111000
  2827.     Dc.B    %01010100
  2828.  
  2829. C12    Dc.B    %00011000    ;' + '
  2830.     Dc.B    %00011000
  2831.     Dc.B    %01111110
  2832.     Dc.B    %00011000
  2833.     Dc.B    %00011000
  2834.  
  2835. C13    Dc.B    %11000000    ;' , '
  2836.     Dc.B    %01100000
  2837.     Dc.B    %00000000
  2838.     Dc.B    %00000000
  2839.     Dc.B    %00000000
  2840.  
  2841. C14    Dc.B    %00000000    ;' - '
  2842.     Dc.B    %00000000
  2843.     Dc.B    %01111110
  2844.     Dc.B    %00000000
  2845.     Dc.B    %00000000
  2846.  
  2847. C15    Dc.B    %00110000    ;' . '
  2848.     Dc.B    %00000000
  2849.     Dc.B    %00000000
  2850.     Dc.B    %00000000
  2851.     Dc.B    %00000000
  2852.  
  2853. C16    Dc.B    %01100000    ;' / '
  2854.     Dc.B    %00110000
  2855.     Dc.B    %00011000
  2856.     Dc.B    %00001100
  2857.     Dc.B    %00000110
  2858.  
  2859. C17    Dc.B    %00111100    ;' 0 '
  2860.     Dc.B    %01100110
  2861.     Dc.B    %01110110
  2862.     Dc.B    %01101110
  2863.     Dc.B    %00111100
  2864.  
  2865. C18    Dc.B    %00001100    ;' 1 '
  2866.     Dc.B    %00001100
  2867.     Dc.B    %00001100
  2868.     Dc.B    %00111100
  2869.     Dc.B    %00011100
  2870.  
  2871. C19    Dc.B    %01111110    ;' 2 '
  2872.     Dc.B    %00110000
  2873.     Dc.B    %00001100
  2874.     Dc.B    %00000110
  2875.     Dc.B    %01111100
  2876.  
  2877. C20    Dc.B    %01111100    ;' 3 '
  2878.     Dc.B    %00000110
  2879.     Dc.B    %00111100
  2880.     Dc.B    %00000110
  2881.     Dc.B    %01111100
  2882.  
  2883. C21    Dc.B    %00001100    ;' 4 '
  2884.     Dc.B    %11111110
  2885.     Dc.B    %01101100
  2886.     Dc.B    %00111100
  2887.     Dc.B    %00011100
  2888.  
  2889. C22    Dc.B    %01111100    ;' 5 '
  2890.     Dc.B    %00000110
  2891.     Dc.B    %01111100
  2892.     Dc.B    %01100000
  2893.     Dc.B    %01111110
  2894.  
  2895. C23    Dc.B    %00111100    ;' 6 '
  2896.     Dc.B    %01100110
  2897.     Dc.B    %01111100
  2898.     Dc.B    %01100000
  2899.     Dc.B    %00111000
  2900.  
  2901. C24    Dc.B    %00011000    ;' 7 '
  2902.     Dc.B    %00011000
  2903.     Dc.B    %00001100
  2904.     Dc.B    %00000110
  2905.     Dc.B    %01111110
  2906.  
  2907. C25    Dc.B    %00111100    ;' 8 '
  2908.     Dc.B    %01100110
  2909.     Dc.B    %00111100
  2910.     Dc.B    %01100110
  2911.     Dc.B    %00111100
  2912.  
  2913. C26    Dc.B    %00011100    ;' 9 '
  2914.     Dc.B    %00000110
  2915.     Dc.B    %00111110
  2916.     Dc.B    %01100110
  2917.     Dc.B    %00111100
  2918.  
  2919. C27    Dc.B    %00000000    ;' : '
  2920.     Dc.B    %00110000
  2921.     Dc.B    %00000000
  2922.     Dc.B    %00110000
  2923.     Dc.B    %00000000
  2924.  
  2925. C28    Dc.B    %01100000    ;' ; '
  2926.     Dc.B    %00110000
  2927.     Dc.B    %00000000
  2928.     Dc.B    %00110000
  2929.     Dc.B    %00000000
  2930.  
  2931. C29    Dc.B    %00011000    ;' < '
  2932.     Dc.B    %00110000
  2933.     Dc.B    %01100000
  2934.     Dc.B    %00110000
  2935.     Dc.B    %00011000
  2936.  
  2937. C30    Dc.B    %00000000    ;' = '
  2938.     Dc.B    %01111110
  2939.     Dc.B    %00000000
  2940.     Dc.B    %01111110
  2941.     Dc.B    %00000000
  2942.  
  2943. C31    Dc.B    %00011000    ;' > '
  2944.     Dc.B    %00001100
  2945.     Dc.B    %00000110
  2946.     Dc.B    %00001100
  2947.     Dc.B    %00011000
  2948.  
  2949. C32    Dc.B    %00011000    ;' ? '
  2950.     Dc.B    %00000000
  2951.     Dc.B    %00011000
  2952.     Dc.B    %01001110
  2953.     Dc.B    %00111100
  2954.  
  2955. C33    Dc.B    %00111110    ;' @ '
  2956.     Dc.B    %01100000
  2957.     Dc.B    %01101110
  2958.     Dc.B    %01100110
  2959.     Dc.B    %00111100
  2960.  
  2961. C34    Dc.B    %01100110    ;' A '
  2962.     Dc.B    %01100110
  2963.     Dc.B    %01111110
  2964.     Dc.B    %01100110
  2965.     Dc.B    %00111100
  2966.  
  2967. C35    Dc.B    %01111100    ;' B '
  2968.     Dc.B    %01100110
  2969.     Dc.B    %01111100
  2970.     Dc.B    %01100110
  2971.     Dc.B    %01111100
  2972.  
  2973. C36    Dc.B    %00111100    ;' C '
  2974.     Dc.B    %01100110
  2975.     Dc.B    %01100000
  2976.     Dc.B    %01100110
  2977.     Dc.B    %00111100
  2978.  
  2979. C37    Dc.B    %01111100    ;' D '
  2980.     Dc.B    %01100110
  2981.     Dc.B    %01100110
  2982.     Dc.B    %01100110
  2983.     Dc.B    %01111100
  2984.  
  2985. C38    Dc.B    %01111110    ;' E '
  2986.     Dc.B    %01100000
  2987.     Dc.B    %01111100
  2988.     Dc.B    %01100000
  2989.     Dc.B    %01111110
  2990.  
  2991. C39    Dc.B    %01100000    ;' F '
  2992.     Dc.B    %01100000
  2993.     Dc.B    %01111100
  2994.     Dc.B    %01100000
  2995.     Dc.B    %01111110
  2996.  
  2997. C40    Dc.B    %00111110    ;' G '
  2998.     Dc.B    %01100110
  2999.     Dc.B    %01101110
  3000.     Dc.B    %01100000
  3001.     Dc.B    %00111110
  3002.  
  3003. C41    Dc.B    %01100110    ;' H '
  3004.     Dc.B    %01100110
  3005.     Dc.B    %01111110
  3006.     Dc.B    %01100110
  3007.     Dc.B    %01100110
  3008.  
  3009. C42    Dc.B    %00111100    ;' I '
  3010.     Dc.B    %00011000
  3011.     Dc.B    %00011000
  3012.     Dc.B    %00011000
  3013.     Dc.B    %00111100
  3014.  
  3015. C43    Dc.B    %00111100    ;' J '
  3016.     Dc.B    %01100110
  3017.     Dc.B    %00000110
  3018.     Dc.B    %00000110
  3019.     Dc.B    %00000110
  3020.  
  3021. C44    Dc.B    %01100110    ;' K '
  3022.     Dc.B    %01101100
  3023.     Dc.B    %01111000
  3024.     Dc.B    %01101100
  3025.     Dc.B    %01100110
  3026.  
  3027. C45    Dc.B    %01111110    ;' L '
  3028.     Dc.B    %01100000
  3029.     Dc.B    %01100000
  3030.     Dc.B    %01100000
  3031.     Dc.B    %01100000
  3032.  
  3033. C46    Dc.B    %01100110    ;' M '
  3034.     Dc.B    %01100110
  3035.     Dc.B    %01111110
  3036.     Dc.B    %01100110
  3037.     Dc.B    %01000010
  3038.  
  3039. C47    Dc.B    %01100110    ;' N '
  3040.     Dc.B    %01101110
  3041.     Dc.B    %01111110
  3042.     Dc.B    %01110110
  3043.     Dc.B    %01100110
  3044.  
  3045. C48    Dc.B    %00111100    ;' O '
  3046.     Dc.B    %01100110
  3047.     Dc.B    %01100110
  3048.     Dc.B    %01100110
  3049.     Dc.B    %00111100
  3050.  
  3051. C49    Dc.B    %01100000    ;' P '
  3052.     Dc.B    %01100000
  3053.     Dc.B    %01111100
  3054.     Dc.B    %01100110
  3055.     Dc.B    %01111100
  3056.  
  3057. C50    Dc.B    %00111111    ;' Q '
  3058.     Dc.B    %01110110
  3059.     Dc.B    %01101110
  3060.     Dc.B    %01100110
  3061.     Dc.B    %00111100
  3062.  
  3063. C51    Dc.B    %01100110    ;' R '
  3064.     Dc.B    %01100110
  3065.     Dc.B    %01111100
  3066.     Dc.B    %01100110
  3067.     Dc.B    %01111100
  3068.  
  3069. C52    Dc.B    %01111100    ;' S '
  3070.     Dc.B    %00000110
  3071.     Dc.B    %00111100
  3072.     Dc.B    %01100000
  3073.     Dc.B    %00111110
  3074.  
  3075. C53    Dc.B    %00011000    ;' T '
  3076.     Dc.B    %00011000
  3077.     Dc.B    %00011000
  3078.     Dc.B    %00011000
  3079.     Dc.B    %01111110
  3080.  
  3081. C54    Dc.B    %00111100    ;' U '
  3082.     Dc.B    %01100110
  3083.     Dc.B    %01100110
  3084.     Dc.B    %01100110
  3085.     Dc.B    %01100110
  3086.  
  3087. C55    Dc.B    %00011000    ;' V '
  3088.     Dc.B    %00111100
  3089.     Dc.B    %01100110
  3090.     Dc.B    %01100110
  3091.     Dc.B    %01100110
  3092.  
  3093. C56    Dc.B    %01000010    ;' W '
  3094.     Dc.B    %01100110
  3095.     Dc.B    %01111110
  3096.     Dc.B    %01100110
  3097.     Dc.B    %01100110
  3098.  
  3099. C57    Dc.B    %01100110    ;' X '
  3100.     Dc.B    %00111100
  3101.     Dc.B    %00011000
  3102.     Dc.B    %00111100
  3103.     Dc.B    %01100110
  3104.  
  3105. C58    Dc.B    %00011000    ;' Y '
  3106.     Dc.B    %00011000
  3107.     Dc.B    %00111100
  3108.     Dc.B    %01100110
  3109.     Dc.B    %01100110
  3110.  
  3111. C59    Dc.B    %01111110    ;' Z '
  3112.     Dc.B    %00110000
  3113.     Dc.B    %00011000
  3114.     Dc.B    %00001100
  3115.     Dc.B    %01111110
  3116.  
  3117. C60    Dc.B    %00001110    ;' [ '
  3118.     Dc.B    %00001100
  3119.     Dc.B    %00001100
  3120.     Dc.B    %00001100
  3121.     Dc.B    %00001110
  3122.  
  3123. C61    Dc.B    %00000110    ;' / '
  3124.     Dc.B    %00001100
  3125.     Dc.B    %00011000
  3126.     Dc.B    %00110000
  3127.     Dc.B    %01100000
  3128.  
  3129. C62    Dc.B    %01110000    ;' ] '
  3130.     Dc.B    %00110000
  3131.     Dc.B    %00110000
  3132.     Dc.B    %00110000
  3133.     Dc.B    %01110000
  3134.  
  3135. C63    Dc.B    %00000000    ;' ^ '
  3136.     Dc.B    %00000000
  3137.     Dc.B    %11001100
  3138.     Dc.B    %01111000
  3139.     Dc.B    %00110000
  3140.  
  3141. C64    Dc.B    %11111110    ;' _ '
  3142.     Dc.B    %00000000
  3143.     Dc.B    %00000000
  3144.     Dc.B    %00000000
  3145.     Dc.B    %00000000
  3146.  
  3147. C65    Dc.B    %00000000    ;' ` '
  3148.     Dc.B    %00000000
  3149.     Dc.B    %00000000
  3150.     Dc.B    %00110000
  3151.     Dc.B    %01100000
  3152.  
  3153. C66    Dc.B    %11111110    ;"Illegal char" character.
  3154.     Dc.B    %11000110
  3155.     Dc.B    %11000110
  3156.     Dc.B    %11000110
  3157.     Dc.B    %11111110
  3158.  
  3159.  
  3160. ; These are the various status text strings.  Each is twelve characters long, so
  3161. ; I don't have to erase bits of strings left behind on the screen...
  3162.  
  3163. NoModText    Dc.B    " NO  MODULE ",0
  3164. IdleText    Dc.B    "    IDLE    ",0
  3165. PlayingText    Dc.B    "  ROCKIN'!  ",0
  3166. PausedText    Dc.B    "   PAUSED   ",0
  3167. StoppedText    Dc.B    "  STOPPED!  ",0
  3168. PSDoneText    Dc.B    "PLAYSEQ DONE",0
  3169.  
  3170.         Even
  3171.  
  3172. ; These four parameters are required solely by the cback.o code.  I'll be having
  3173. ; nuttin' to do wit' 'em... :)
  3174.  
  3175. _BackGroundIO    Dc.L    0        ;This stuff
  3176. _priority    Dc.L    0        ;is only here
  3177. _stack        Dc.L    4000        ;because I'm linking
  3178. _procname    Dc.L    ProgName    ;with cback.o. Grrr!
  3179.  
  3180. ;==============================
  3181. ;
  3182. ; Grrrr!  cback.o wants to store to absolute memory locations, so I need
  3183. ; this block storage segment (I'd prefer to have all my variables allocated
  3184. ; as one block of memory and referenced off an address register. Grrrr!)
  3185. ; One of these days I'm gonna hafta modify newcback.o and teach it about
  3186. ; pure code (*Sigh*).  Of course, I'm no angel either, since I did the same
  3187. ; damn thing with NWScreen in my NewWindow structure.  Blech...
  3188.  
  3189.         BSS
  3190.         Even
  3191.  
  3192. DOSBase        Ds.L    1    ;I don't even NEED this variable. Grrrr!
  3193.  
  3194.         End
  3195.